C
@backtrader
I have asked for a legacy account . at the end of the year legacy account wont access the api service anymore.
I try with the legacy account (2121212 )
here the code :
from future import (absolute_import, division, print_function,
unicode_literals)
import argparse
import datetime
The above could be sent to an independent module
import backtrader as bt
from backtrader.utils import flushfile # win32 quick stdout flushing
StoreCls = bt.stores.OandaStore
DataCls = bt.feeds.OandaData
#BrokerCls = bt.brokers.OandaBroker
class TestStrategy(bt.Strategy):
params = dict(
smaperiod=5,
trade=False,
stake=10,
exectype=bt.Order.Market,
stopafter=0,
valid=None,
cancel=0,
donotcounter=False,
sell=False,
usebracket=False,
)
def __init__(self):
# To control operation entries
self.orderid = list()
self.order = None
self.counttostop = 0
self.datastatus = 0
# Create SMA on 2nd data
self.sma = bt.indicators.MovAv.SMA(self.data, period=self.p.smaperiod)
print('--------------------------------------------------')
print('Strategy Created')
print('--------------------------------------------------')
def notify_data(self, data, status, *args, **kwargs):
print('*' * 5, 'DATA NOTIF:', data._getstatusname(status), *args)
if status == data.LIVE:
self.counttostop = self.p.stopafter
self.datastatus = 1
def notify_store(self, msg, *args, **kwargs):
print('*' * 5, 'STORE NOTIF:', msg)
def notify_order(self, order):
if order.status in [order.Completed, order.Cancelled, order.Rejected]:
self.order = None
print('-' * 50, 'ORDER BEGIN', datetime.datetime.now())
print(order)
print('-' * 50, 'ORDER END')
def notify_trade(self, trade):
print('-' * 50, 'TRADE BEGIN', datetime.datetime.now())
print(trade)
print('-' * 50, 'TRADE END')
def prenext(self):
self.next(frompre=True)
def next(self, frompre=False):
txt = list()
txt.append('Data0')
txt.append('%04d' % len(self.data0))
dtfmt = '%Y-%m-%dT%H:%M:%S.%f'
txt.append('{:f}'.format(self.data.datetime[0]))
txt.append('%s' % self.data.datetime.datetime(0).strftime(dtfmt))
txt.append('{:f}'.format(self.data.open[0]))
txt.append('{:f}'.format(self.data.high[0]))
txt.append('{:f}'.format(self.data.low[0]))
txt.append('{:f}'.format(self.data.close[0]))
txt.append('{:6d}'.format(int(self.data.volume[0])))
txt.append('{:d}'.format(int(self.data.openinterest[0])))
txt.append('{:f}'.format(self.sma[0]))
print(', '.join(txt))
if len(self.datas) > 1 and len(self.data1):
txt = list()
txt.append('Data1')
txt.append('%04d' % len(self.data1))
dtfmt = '%Y-%m-%dT%H:%M:%S.%f'
txt.append('{}'.format(self.data1.datetime[0]))
txt.append('%s' % self.data1.datetime.datetime(0).strftime(dtfmt))
txt.append('{}'.format(self.data1.open[0]))
txt.append('{}'.format(self.data1.high[0]))
txt.append('{}'.format(self.data1.low[0]))
txt.append('{}'.format(self.data1.close[0]))
txt.append('{}'.format(self.data1.volume[0]))
txt.append('{}'.format(self.data1.openinterest[0]))
txt.append('{}'.format(float('NaN')))
print(', '.join(txt))
if self.counttostop: # stop after x live lines
self.counttostop -= 1
if not self.counttostop:
self.env.runstop()
return
if not self.p.trade:
return
if self.datastatus and not self.position and len(self.orderid) < 1:
if not self.p.usebracket:
if not self.p.sell:
# price = round(self.data0.close[0] * 0.90, 2)
price = self.data0.close[0] - 0.005
self.order = self.buy(size=self.p.stake,
exectype=self.p.exectype,
price=price,
valid=self.p.valid)
else:
# price = round(self.data0.close[0] * 1.10, 4)
price = self.data0.close[0] - 0.05
self.order = self.sell(size=self.p.stake,
exectype=self.p.exectype,
price=price,
valid=self.p.valid)
else:
print('USING BRACKET')
price = self.data0.close[0] - 0.05
self.order, _, _ = self.buy_bracket(size=self.p.stake,
exectype=bt.Order.Market,
price=price,
stopprice=price - 0.10,
limitprice=price + 0.10,
valid=self.p.valid)
self.orderid.append(self.order)
elif self.position and not self.p.donotcounter:
if self.order is None:
if not self.p.sell:
self.order = self.sell(size=self.p.stake // 2,
exectype=bt.Order.Market,
price=self.data0.close[0])
else:
self.order = self.buy(size=self.p.stake // 2,
exectype=bt.Order.Market,
price=self.data0.close[0])
self.orderid.append(self.order)
elif self.order is not None and self.p.cancel:
if self.datastatus > self.p.cancel:
self.cancel(self.order)
if self.datastatus:
self.datastatus += 1
def start(self):
if self.data0.contractdetails is not None:
print('-- Contract Details:')
print(self.data0.contractdetails)
header = ['Datetime', 'Open', 'High', 'Low', 'Close', 'Volume',
'OpenInterest', 'SMA']
print(', '.join(header))
self.done = False
def runstrategy():
args = parse_args()
# Create a cerebro
cerebro = bt.Cerebro()
storekwargs = dict(
token=args.token,
account=args.account,
practice=not args.live
)
if not args.no_store:
store = StoreCls(**storekwargs)
if args.broker:
if args.no_store:
broker = BrokerCls(**storekwargs)
else:
broker = store.getbroker()
cerebro.setbroker(broker)
timeframe = bt.TimeFrame.TFrame(args.timeframe)
# Manage data1 parameters
tf1 = args.timeframe1
tf1 = bt.TimeFrame.TFrame(tf1) if tf1 is not None else timeframe
cp1 = args.compression1
cp1 = cp1 if cp1 is not None else args.compression
if args.resample or args.replay:
datatf = datatf1 = bt.TimeFrame.Ticks
datacomp = datacomp1 = 1
else:
datatf = timeframe
datacomp = args.compression
datatf1 = tf1
datacomp1 = cp1
fromdate = None
if args.fromdate:
dtformat = '%Y-%m-%d' + ('T%H:%M:%S' * ('T' in args.fromdate))
fromdate = datetime.datetime.strptime(args.fromdate, dtformat)
DataFactory = DataCls if args.no_store else store.getdata
datakwargs = dict(
timeframe=datatf, compression=datacomp,
qcheck=args.qcheck,
historical=args.historical,
fromdate=fromdate,
bidask=args.bidask,
useask=args.useask,
backfill_start=not args.no_backfill_start,
backfill=not args.no_backfill,
tz=args.timezone
)
if args.no_store and not args.broker: # neither store nor broker
datakwargs.update(storekwargs) # pass the store args over the data
data0 = DataFactory(dataname=args.data0, **datakwargs)
data1 = None
if args.data1 is not None:
if args.data1 != args.data0:
datakwargs['timeframe'] = datatf1
datakwargs['compression'] = datacomp1
data1 = DataFactory(dataname=args.data1, **datakwargs)
else:
data1 = data0
rekwargs = dict(
timeframe=timeframe, compression=args.compression,
bar2edge=not args.no_bar2edge,
adjbartime=not args.no_adjbartime,
rightedge=not args.no_rightedge,
takelate=not args.no_takelate,
)
if args.replay:
cerebro.replaydata(data0, **rekwargs)
if data1 is not None:
rekwargs['timeframe'] = tf1
rekwargs['compression'] = cp1
cerebro.replaydata(data1, **rekwargs)
elif args.resample:
cerebro.resampledata(data0, **rekwargs)
if data1 is not None:
rekwargs['timeframe'] = tf1
rekwargs['compression'] = cp1
cerebro.resampledata(data1, **rekwargs)
else:
cerebro.adddata(data0)
if data1 is not None:
cerebro.adddata(data1)
if args.valid is None:
valid = None
else:
valid = datetime.timedelta(seconds=args.valid)
# Add the strategy
cerebro.addstrategy(TestStrategy,
smaperiod=args.smaperiod,
trade=args.trade,
exectype=bt.Order.ExecType(args.exectype),
stake=args.stake,
stopafter=args.stopafter,
valid=valid,
cancel=args.cancel,
donotcounter=args.donotcounter,
sell=args.sell,
usebracket=args.usebracket)
# Live data ... avoid long data accumulation by switching to "exactbars"
cerebro.run(exactbars=args.exactbars)
if args.exactbars < 1: # plotting is possible
if args.plot:
pkwargs = dict(style='line')
if args.plot is not True: # evals to True but is not True
npkwargs = eval('dict(' + args.plot + ')') # args were passed
pkwargs.update(npkwargs)
cerebro.plot(**pkwargs)
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='Test Oanda integration')
parser.add_argument('--exactbars', default=1, type=int,
required=False, action='store',
help='exactbars level, use 0/-1/-2 to enable plotting')
parser.add_argument('--stopafter', default=0, type=int,
required=False, action='store',
help='Stop after x lines of LIVE data')
parser.add_argument('--no-store',
required=False, action='store_true',
help='Do not use the store pattern')
parser.add_argument('--debug',
required=False, action='store_true',
help='Display all info received from source')
parser.add_argument('--token', default=None,
required=True, action='store',
help='Access token to use')
parser.add_argument('--account', default=None,
required=True, action='store',
help='Account identifier to use')
parser.add_argument('--live', default=None,
required=False, action='store',
help='Go to live server rather than practice')
parser.add_argument('--qcheck', default=0.5, type=float,
required=False, action='store',
help=('Timeout for periodic '
'notification/resampling/replaying check'))
parser.add_argument('--data0', default=None,
required=True, action='store',
help='data 0 into the system')
parser.add_argument('--data1', default=None,
required=False, action='store',
help='data 1 into the system')
parser.add_argument('--timezone', default=None,
required=False, action='store',
help='timezone to get time output into (pytz names)')
parser.add_argument('--bidask', default=None,
required=False, action='store_true',
help='Use bidask ... if False use midpoint')
parser.add_argument('--useask', default=None,
required=False, action='store_true',
help='Use the "ask" of bidask prices/streaming')
parser.add_argument('--no-backfill_start',
required=False, action='store_true',
help='Disable backfilling at the start')
parser.add_argument('--no-backfill',
required=False, action='store_true',
help='Disable backfilling after a disconnection')
parser.add_argument('--historical',
required=False, action='store_true',
help='do only historical download')
parser.add_argument('--fromdate',
required=False, action='store',
help=('Starting date for historical download '
'with format: YYYY-MM-DD[THH:MM:SS]'))
parser.add_argument('--smaperiod', default=5, type=int,
required=False, action='store',
help='Period to apply to the Simple Moving Average')
pgroup = parser.add_mutually_exclusive_group(required=False)
pgroup.add_argument('--replay',
required=False, action='store_true',
help='replay to chosen timeframe')
pgroup.add_argument('--resample',
required=False, action='store_true',
help='resample to chosen timeframe')
parser.add_argument('--timeframe', default=bt.TimeFrame.Names[1],
choices=bt.TimeFrame.Names,
required=False, action='store',
help='TimeFrame for Resample/Replay')
parser.add_argument('--compression', default=1, type=int,
required=False, action='store',
help='Compression for Resample/Replay')
parser.add_argument('--timeframe1', default=None,
choices=bt.TimeFrame.Names,
required=False, action='store',
help='TimeFrame for Resample/Replay - Data1')
parser.add_argument('--compression1', default=None, type=int,
required=False, action='store',
help='Compression for Resample/Replay - Data1')
parser.add_argument('--no-takelate',
required=False, action='store_true',
help=('resample/replay, do not accept late samples'))
parser.add_argument('--no-bar2edge',
required=False, action='store_true',
help='no bar2edge for resample/replay')
parser.add_argument('--no-adjbartime',
required=False, action='store_true',
help='no adjbartime for resample/replay')
parser.add_argument('--no-rightedge',
required=False, action='store_true',
help='no rightedge for resample/replay')
parser.add_argument('--broker',
required=False, action='store_true',
help='Use Oanda as broker')
parser.add_argument('--trade',
required=False, action='store_true',
help='Do Sample Buy/Sell operations')
parser.add_argument('--sell',
required=False, action='store_true',
help='Start by selling')
parser.add_argument('--usebracket',
required=False, action='store_true',
help='Test buy_bracket')
parser.add_argument('--donotcounter',
required=False, action='store_true',
help='Do not counter the 1st operation')
parser.add_argument('--exectype', default=bt.Order.ExecTypes[0],
choices=bt.Order.ExecTypes,
required=False, action='store',
help='Execution to Use when opening position')
parser.add_argument('--stake', default=10, type=int,
required=False, action='store',
help='Stake to use in buy operations')
parser.add_argument('--valid', default=None, type=float,
required=False, action='store',
help='Seconds to keep the order alive (0 means DAY)')
parser.add_argument('--cancel', default=0, type=int,
required=False, action='store',
help=('Cancel a buy order after n bars in operation,'
' to be combined with orders like Limit'))
# Plot options
parser.add_argument('--plot', '-p', nargs='?', required=False,
metavar='kwargs', const=True,
help=('Plot the read data applying any kwargs passed\n'
'\n'
'For example (escape the quotes if needed):\n'
'\n'
' --plot style="candle" (to plot candles)\n'))
if pargs is not None:
return parser.parse_args(pargs)
return parser.parse_args()
if name == 'main':
runstrategy()