For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

strategy.getposition returning different values for same ticker on different timeframes



  • 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...")
    

  • administrators

    Your (A)I is far more advanced that the rest of the AIs in algotrading (non-existent AIs in fact) which makes you think that things are understood as you understand them.

    @Mark-Weaver said in strategy.getposition returning different values for same ticker on different timeframes:

    the posSize value is retrieved via

    for i, d in enumerate(self.datas):
                posSize = self.getposition(d).size
    

    Even if you know that they are the same "ticker" because you have personally added them, the code cannot know it. They are different data feeds, full stop. If they are the same or not is something you have to know and manage.

    And for each data feed a separate position accounting is kept, hence your result.



  • @backtrader hehe fair enough & clever. But that begs the question, if I have a DataFeed for FCEL on a 5m aggregation, and I send a buy order through the broker API, what is it actually buying, that's different than, say, the underlying instrument behind the FCEL datafeed on a 1M aggregration?

    I expected that there was a member variable within the DataFeed representing the symbol itself, independent of timeframe, but i was not able to see it in docs, or in dir(data), or elsewhere. I don't see it as a parameter in the buy function. I just see data relating back to the symbol. So why would the broker interface return different position values for FCEL 5M vs FCEL 1M? Is that how it would work in live trading?



  • @Mark-Weaver Also, please don't assume that I'm expecting magical behavior out of this. I already have code which is attempting to manage my position sizes without having to rely on that particular broker call. Above is just an example to demonstrate the particular issue and question I have about it, because this behavior didn't immediately make sense to me


  • administrators

    @Mark-Weaver said in strategy.getposition returning different values for same ticker on different timeframes:

    I expected

    You want to do "algotrading", remove then "expect" from your vocabulary. As soon as possible.

    @Mark-Weaver said in strategy.getposition returning different values for same ticker on different timeframes:

    if I have a DataFeed for FCEL on a 5m aggregation, and I send a buy order through the broker API, what is it actually buying, that's different than, say, the underlying instrument behind the FCEL datafeed on a 1M aggregration?

    You know nothing is different. But the code treats each single data feed as an independent data feed. Hence accounting is different.

    Why should the code be making efforts to try to identify things as being the same thing? That will fail in an epic manner when the data feed provider provides no identification means.

    Your AI is still believing that there are many other AI entities in place.

    @Mark-Weaver said in strategy.getposition returning different values for same ticker on different timeframes:

    Is that how it would work in live trading?

    I don't know, I didn't write the alpaca broker, you will have to ask alpaca, but I guess it will be so.

    @Mark-Weaver said in strategy.getposition returning different values for same ticker on different timeframes:

    I don't see it as a parameter in the buy function

    The buy method has a clear parameter data which is the target of your acquisition. Track anything you want on 5min and buy the 1min feed always (and check its position)

    @Mark-Weaver said in strategy.getposition returning different values for same ticker on different timeframes:

    So why would the broker interface return different position values for FCEL 5M vs FCEL 1M?

    Because they are different data feeds.



  • @backtrader OK thanks for response :) It has nothing to do with me expecting an AI to have belief in other AI entities or any of whatever you're trying to imply.

    It has to do with the simple expectation--of a framework--that a BUY order executed for a given symbol will have a position size reflected in any query on that same symbol, regardless of whatever timeframe the orders or queries are being executed on. It is counter-intuitive to operate in any other way.

    I will work around that, and I will see what Alpaca has to say and post back here if its relevant. Cheers!


Log in to reply
 

});