The gist here is to generate a signal on a larger timeframe (e.g. 5M) and trigger a buy off a smaller timeframe (e.g. 1M).. I am using Alpaca as the broker here, and have not ruled out that it could be an issue there.
I am seeing BUYS on the smaller timeframe, but cannot retrieve accurate position information on the larger timeframe. It is as if the broker is treating these both as 2 separate tickers
You can see that the position only increases on the smaller timeframe:
enumerating in next! name: FCEL compression: 1 posSize = 300 2020-02-03 14:24:00 cash: 9534.0 close: 1.56
enumerating in next! name: FCEL compression: 5 posSize = 0 2020-02-03 14:20:00 cash: 9534.0 close: 1.55
setting signalHigh: 1.55.. will buy if we close over it on the smaller timeframe
next!
enumerating in next! name: FCEL compression: 1 posSize = 400 2020-02-03 14:25:00 cash: 9379.0 close: 1.55
enumerating in next! name: FCEL compression: 5 posSize = 0 2020-02-03 14:25:00 cash: 9379.0 close: 1.55
setting signalHigh: 1.56.. will buy if we close over it on the smaller timeframe:
the posSize value is retrieved via
for i, d in enumerate(self.datas):
posSize = self.getposition(d).size
I have tried mucking with the datanames in the DataFeeds.. I have tired using 2 separately created DataFeeds, and 1 DataFeed along with a resampled feed
Code example:
import alpaca_backtrader_api
import backtrader as bt
import conf
from datetime import datetime
# 14:30:00 GMT is market open!
ALPACA_API_KEY = conf.paper_api_key
ALPACA_SECRET_KEY = conf.paper_api_secret
ALPACA_PAPER = True
triggerPeriod = 1
signalPeriod = 5
class TestyStrat(bt.Strategy): # for demo'ing issue
params = (('signalCompression',30),('triggerCompression',5),)
def __init__(self):
print(f"init TestyStrat # datas: {len(self.datas)}")
self.ema8_map = {}
self.signalHigh = None
for i, d in enumerate(self.datas):
print(f" TestyStrat enumerating {d._name} compression={d._compression} {dir(d)}")
# dir(d)
if d._compression==self.p.signalCompression:
self.ema8_map[d._name] = bt.ind.EMA(d.close, period=8)
print("Done with init TestyStrat")
def next(self):
print("\nnext!")
for i, d in enumerate(self.datas):
posSize = self.getposition(d).size
print(f"enumerating in next! name: {d._name} compression: {d._compression} posSize = {posSize} {d.num2date()} cash: {self.broker.get_cash()} close: {d.close[0]}")
if d._compression==self.p.signalCompression:
# we just trigger SELLS on this larger timeframe
if self.ema8_map[d._name][0] > self.ema8_map[d._name][-1]:
print(f" setting signalHigh: {d.high[0]}.. will buy if we close over it on the smaller timeframe")
self.signalHigh = d.high[0]
elif d._compression==self.p.triggerCompression:
# we just trigger BUYS on this smaller timeframe
if self.signalHigh is not None and d.close[0] > self.signalHigh:
self.buy(d, 100)
# end class TestyStrat -------------
cerebro = bt.Cerebro(writer=True)
# cerebro.addstrategy(AscPairMAsByATRStrategy)
cerebro.addstrategy(TestyStrat,signalCompression=signalPeriod, triggerCompression=triggerPeriod) #{'signalCompression':5, 'triggerCompression':2}))
#cerebro.addstrategy(SmaCross)
cerebro.addsizer(bt.sizers.PercentSizerInt, percents=25)
print("Added sizer")
store = alpaca_backtrader_api.AlpacaStore(
key_id=ALPACA_API_KEY,
secret_key=ALPACA_SECRET_KEY,
paper=ALPACA_PAPER
)
if not ALPACA_PAPER:
broker = store.getbroker() # or just alpaca_backtrader_api.AlpacaBroker()
cerebro.setbroker(broker)
DataFactory = store.getdata # or use alpaca_backtrader_api.AlpacaData
def addData(symbol):
trigger = DataFactory(dataname=symbol, historical=True, fromdate=datetime(2020,2,3),
todate=datetime(2020,2,6),
timeframe=bt.TimeFrame.Minutes, compression=triggerPeriod)
# smallest timeframes FIRST!!
cerebro.adddata(trigger, name=symbol) # name=f"{symbol}{triggerPeriod}m"
cerebro.resampledata(trigger, timeframe=bt.TimeFrame.Minutes, compression=signalPeriod, name=symbol)
addData("FCEL")
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
cerebro.run()
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
cerebro.plot(style='candlestick',barup='green', bardown='red')
print("fini...")