Power futures settlement



  • Hi all,

    I'm trying to use backtrader for backtesting trading strategies on power futures products.

    Description of my case:

    My products concerns weekly power delivery: each delivery week is a different product.

    Date	        Close	Week id
    01/08/2016	27.09	W1         <--- all the prices with weekid W1 concern 
    02/08/2016	27.46	W1         ----- a delivery of the power during the next week (id W2)
    03/08/2016	27.5	W1
    04/08/2016	27.04	W1
    05/08/2016	26.94	W1
    08/08/2016	27.29	W2
    09/08/2016	27.08	W2
    10/08/2016	26.82	W2
    11/08/2016	26.98	W2
    12/08/2016	27.81	W2
    15/08/2016	28.12	W3
    16/08/2016	27.78	W3
    17/08/2016	28.1	W3
    18/08/2016	28.73	W3
    19/08/2016	28.75	W3
    

    I can buy and sell a weekly product until the trading day before the start of the delivery: in my case, the previous friday.

    • If I buy 1 unit on 02/08/2016 @ 27.46 I have until 05/08/2016 (incl.) to sell it.

    • If I don't sell it before W2, there is an automatic "settlement" at spot day ahead (prower day ahead exchange price)

    In backtrader:

    • I have one data stream representing future price (as in my example) (data0)
      and on data stream representing my settlement price (data1)

    What I try to do:

    In my next method:

    • If currentline.weekid != lastline.weekid: # it means that we just entered in a new week

      • If a position is already opened @ data0.close:
        • I must close the position @ data1.close
    • Then, I can reopen a position on data0.

    My questions:

    Has anybody tried to to something like this ?
    Is there a way to do this ?


  • administrators

    The lines in the objects are actually floats. That means that an id like W1 cannot be used.

    But the W1 could be parsed and translated to 1 and so on until W52 which would be translated to 52.

    You can extend a data feed to add that weekid line which is parsed from your data. See these two topics:

    But if those weeks are standard calendar weeks, you can do the same by simply looking up the week with the datetime module. See:

    The strategy has a datetime line and from there you get a date with self.lines.datetime.date() and you can get the isocalendar tuple.

    Keeping track of the second item in the tuple (the ISO Week Number) would be the same as parsing it from a data file.



  • You're right.
    The table in my example is not exactely what I provide to backtrader (this was an illustration for my example). I only feed bt with prices and I use self.datawb.datetime.datetime().isocalendar()[1] to know the week id.
    ==> this is OK

    But my problem is more on the "Buy 1 on data0 and Sell 1 on data1" problem: I can't find a way to do this and have a net position of 0 at the end of each week.


  • administrators

    Something is unclear.

    From the original post:

    If currentline.weekid != lastline.weekid: # it means that we just entered in a new week

    And from the last post:

    problem: I can't find a way to do this and have a net position of 0 at the end of each week.

    Because the code above kicks in when the new week has started. You will never have a net position of 0 and the end of the week. You will be bought into data0.

    To sell at the end of the week you need to know that the current trading day is the end of the week. Options:

    • Your trading asset always trades on Friday (even if the country has some bank holidays on Fridays)

      You need to check that the current day is Friday and sell data1 to be able to buy data0

    • Your trading asset has some missing Fridays because the exchange follows Bank Holidays

      You need extra information to let you know that on particular calendar weeks, the last trading day is not Friday but another (it could be Wednesday for example ...)

    But it also seems like if you wanted to sell with the closing price on Friday. Use cheat-on-close (or else intraday data and Close orders before the market close time)



  • That's true. I need to do it on the last day of the week.
    And the set_coc will help me for sure.

    But what about selling on another instrument (data1) while i bought on data0 ?

    Date Close Week id
    01/08/2016 27.09 W1 <-- buy 1 @27.09
    02/08/2016 27.46 W1
    03/08/2016 27.5 W1
    04/08/2016 27.04 W1
    05/08/2016 26.94 W1 <-- at the end of the week, no oportunity identified by my indicator => so automaticly sell 1 @ data1.close[0] (and not data0.close[0]=26.94)


  • administrators

    This may be a long shot, but are you using self.sell(self.data1, ...) ... ?

    A code sample would be what really shows where your worries are.



  • Here is a sample where I tried to integrate all what we said before:

    def islastdayofweek(self, data):
            return data.datetime.date(0).isocalendar()[1] != data.datetime.date(1).isocalendar()[1]
    
    def next(self):
        islastdayofweek = self.islastdayofweek(self.data0)
        p = self.getposition().size
    
        if (self.signal < 0.0):
            s = self.getsizing(isbuy=True)
            if (p + s <= self.params.limit):
                self.log('BUY CREATE , %.2f, %.2f MWh' % (self.data0.close[0], s))            
                self.buy(size=s)
                p = p + s
            else:
                self.log('BUY LIMIT EXCEEDED. ORDER CANCELLED.')
    
        elif (self.signal > 0.0):
            s = self.getsizing(isbuy=False)
            if (p - s >= 0):
                self.log('SELL CREATE , %.2f, %.2f MWh' % (self.data0.close[0], s))
                self.sell(size=s)
                p = p - s
    
        if islastdayofweek and p > 0:
            self.sell(self.data1, size=p)
            self.log('SELL SETTLEMENT, %.2f, %.2f MWh' % (self.data1.close[0], p))
            # Here, is my position equal to 0 after execution of the order? Or short on data1 and long on data0 ?

  • administrators

    The default action of buy and sell if nothing is specified is to apply the action to data0.

    Should you wish otherwise and as stated above, you should for example: self.sell(self.data1)



  • Ok. When I do this, here is what happens with the positions:

    0_1488438238559_upload-c35dbedb-4b2e-4378-950d-46ede4d926da

    At the end of the 05/08/2016, the position in my example is +5 on data0 and -5 on data1.
    What I want to do is net the position for the next trading day:
    on 08/08/2016: Position 0 on data0 and 0 on data1

    Can I do something like this?


  • administrators

    With that table at hand your desired use case seems clearer.

    But you need to specifically address both data0 and data1. There is nothing which ties both data feeds together, i.e.: an action on one of them buy or sell has no actual effect on the other.

    The platform has no way to know that your wish is that by opening a short position on data1 at the end of Week_N which has the implication that at the start of the Week_N+1 positions on both data0 and data1 have to be closed.

    Let's imagine that somehow a link can be established between data0 and data1. Because you are using 5 and -5 it seems natural to assume that 5 + (-5) = 0. But questions on the implementation of the logic quickly arise

    • Are positions on data0 and data1 simply added? What happens if you buy 5 on data1, should the system then end up with 10 shares on data0?

    • You wish that on the next trading day, but ... Is it always the case? Does it have to be on week boundaries?

    The strange thing about the use case is (there are for sure good reasons for it)

    • Why opening a short position on data1 at the end of week with the expectation to have no positions open on the next trading day?

      It seems easier to simply close the open position on data0



  • @backtrader said in Power futures settlement:

    With that table at hand your desired use case seems clearer.

    But you need to specifically address both data0 and data1. There is nothing which ties both data feeds together, i.e.: an action on one of them buy or sell has no actual effect on the other.

    The platform has no way to know that your wish is that by opening a short position on data1 at the end of Week_N which has the implication that at the start of the Week_N+1 positions on both data0 and data1 have to be closed.

    Let's imagine that somehow a link can be established between data0 and data1. Because you are using 5 and -5 it seems natural to assume that 5 + (-5) = 0. But questions on the implementation of the logic quickly arise

    • Are positions on data0 and data1 simply added? What happens if you buy 5 on data1, should the system then end up with 10 shares on data0?

    • You wish that on the next trading day, but ... Is it always the case? Does it have to be on week boundaries?

    Not always week boundaries. In this case I consider weekly power futures, but I could also deal monthly of quarterly futures for example

    The strange thing about the use case is (there are for sure good reasons for it)

    • Why opening a short position on data1 at the end of week with the expectation to have no positions open on the next trading day?

      It seems easier to simply close the open position on data0

    data0 = weekly power delivery future. When I buy 5 on data0 in W1 it means that, If I don't sell it, I will have a physical delivery of the power on W2.
    This I don't want because I'm not an energy provider. I want to avoid the physical delivery.

    If the 5 are not sold before the delivery week (W2), I will sell the energy on the Spot Day Ahead exchange every day.
    data1 represent the average spot dahead price of the week W2.

    This is why, in this case, I buy 5 on data0 and sell 5 on data1.
    In the end, I really have a net position of 0 because I sold the energy I bought.


  • administrators

    There is an actual link between the 2 feeds in the specific case because both relate to an asset with physical delivery and the action on one cancels the physical delivery of the other.

    The problem as understood

    • In the real world you have a net position of 0 because you sold the energy you bought (preventing actual physical delivery)

    But

    • You are initially still holding 5 units of data0
    • You are initially still holding -5 units of data1

    And you:

    • Expect the backtesting platform to do 5 + (-5) -> 0 on units which are actually being held because there is a physical delivery action associated to those units which are still in your hand.

    It is clear that your actual real-world problem is solved (the energy is delivered, but actually to someone else) making it a zero-sum game, but the units are still there. Of course at the end of the week, the power delivery future expires and the units disappear from your account, but that's not known to the platform and you actually feed it more data for the coming weeks, so there is also no way to tell the platform that the asset no longer exists and the position could be (no such functionality is there) canceled against the last known price.

    One additional question given that data0 expires (the position disappears), but data1 is a spot price

    • What happens with the -5 trade in the real world on data1?


  • @backtrader said in Power futures settlement:

    One additional question given that data0 expires (the position disappears), but data1 is a spot price

    • What happens with the -5 trade in the real world on data1?

    the -5 on data1 are sold on the da ahead spot exchange. It's sold to counterparts of the exchange who need to rebalance their short physical position.


  • administrators

    It seems (and this is due to not knowing how the energy exchanges actually work) that the -5 units of data1 is something you sell, but doesn't stick into your account, i.e.: evolution in the prices of data1 after you have sold the -5 units, have no impact in the cash and/or portfolio value of your account.

    No previous real experience with actual physical delivery and hence the small questions to try to understand how both things are tied together.


  • administrators

    A commit (which may or may not cover the actual use, given the lack of some details) is in the development branch with this commit: https://github.com/mementum/backtrader/commit/19a41a5921c5d9e6ed211d4659d48630c288aa72

    Usage pattern:

    data0 = MyDataFeed(dataname=...)
    cerebro.adddata(data0)
    
    data1 = MyDataFeed(dataname=...)
    data1.compensate(data0)
    cerebro.adddata(data1)
    

    Any buy/sell action on data1 will be executed against data0 in the broker. A long open position of +5 on data0 will be closed by a sell(data=data1, size=5). Commission charges in any case will be those defined for data1 (if any)



  • @backtrader Great! I'll try it
    thanks



  • I think that with your "compensate" method, I'm almost able to do my backtest.

    One more thing:

    when data0's position is 5 and I sell 5 on data1, , the position of data0 is set to 0 thanks to you're new method.

    But the trade is not closed, right ?


  • administrators

    Probably not if you are talking about the Trade instances you get in the strategy's notify_trade method.

    That part remain untouched but would also benefit from considering the compensating data feed.



  • Ok

    Other question:

    I use plotmaster option to plot the two streams on the same plot:

    self.data1.plotinfo.plotmaster = self.data0

    0_1488984941389_upload-c55a1806-3e57-42cb-9da3-abcb0b340b5d

    I expect the two lines (red and black) to share the same y axis. but I'm not sure it's the case here.
    Any idea ?

    Does one of the y axis concern the buy and sell tickers ?


  • administrators

    The 2nd data is plotted sharing the same x-axis but have independent `y-axes'. The rationale

    • The platform cannot predict if both data feeds will have compatible axes.

    In your case the prices are really approximate, but if you consider plotting the SP500 (around 2370 these days) and the DAX (around 12000 these days) the scales are not compatible.

    With all that in mind it could be conceivable to let the user hint if the y-axis can also be shared.


Log in to reply
 

Looks like your connection to Backtrader Community was lost, please wait while we try to reconnect.