kieran-mackle / AutoTrader

A Python-based development platform for automated trading systems - from backtesting to optimisation to livetrading.
https://kieran-mackle.github.io/AutoTrader/
GNU General Public License v3.0
945 stars 217 forks source link

Question about updating open positions #11

Closed elijahho closed 2 years ago

elijahho commented 2 years ago

Hi,

Is there a method to update open positions? Was looking for it but maybe I missed it. Thanks.

kieran-mackle commented 2 years ago

What sort of modifications would you like to make to open positions?

Currently the only means of modifying an open position is via the reduce_position method of the virtual broker. As per the docs, an example signal dict to use this is shown below, which can be used to reduce a long position by 15 units.

signal_dict = {'order_type': 'reduce',
               'direction': -1,
               'size': 15}

Note that this is not implemented in the Oanda broker module yet, so should only be used for backtesting.

There is also of course the option to close a full position via 'order_type': 'close', as noted here.

If there is some other functionality you would like to see, please let me know and I will aim to implement it.

elijahho commented 2 years ago

I see, thanks for pointing me to the relevant parts of the docs.

What I'm looking for is to update stop loss and take profit of open positions based on how the open positions behave, specifically for Oanda. Probably it's as straightforward as exposing a public method update_stop_loss, and update_take_profit, and passing in tradeSpecifier, new_stop_loss or new_take_profit. Happy to discuss further and implement it

kieran-mackle commented 2 years ago

I see, that would be a good addition. My initial idea would be to add a new order type, for example order_type: 'update', and use the related_orders key to specify which trades to modify/update. The specific trade ID's could be obtained using the get_open_trades and get_open_positions methods of the broker module.

Order handling docs

kieran-mackle commented 2 years ago

@elijahho I have now added this functionality in the virtual broker. The order_type: 'modify' can be used with the related_orders key to update the SL and TP of open trades. An example of how this may be used in a strategy to update the SL of a trade is shown below. Note that this code requires the INCLUDE_BROKER: True key to be included in the strategy configuration yaml file, so that the broker object is passed to the strategy (strategy __init__ will have to be similar to __init__(self, params, data, product, broker, broker_utils) to accept broker and utils when INCLUDE_BROKER: True).

# Get trade_ID of existing trade 
open_trade_ID = current_position[self.product]['trade_IDs'][0]      # Returns ID of first open trade returned
trade_details = self.broker.get_trade_details(open_trade_ID)        # Returns trade details dict
current_SL = trade_details['stop_loss']                             # Returns stop loss currently in place on trade 
current_direction = np.sign(trade_details['size'])                  # Returns direction of trade (to determine if long/short)

# Calculate updated SL
new_SL = self.data.Close[i] - self.params['atr_mult']*current_direction*self.atr[i]   # Calculate new SL based on ATR

if current_direction*(new_SL - current_SL) > 0:
    # New stop loss has moved in correct direction, update
    order_type = 'modify'
    signal_dict["stop_loss"] = new_SL
    signal_dict["related_orders"] = open_trade_ID

Note that I have not yet replicated this functionality in the Oanda module.
EDIT: this functionality is now supported by the Oanda broker API (as of version 0.6.3)

elijahho commented 2 years ago

I see, thanks for adding this in!

Question - For this implementation approach, it seems like a major limitation is that user cannot both open or exit a trade AND update TP/SL?

kieran-mackle commented 2 years ago

I'm not sure if I completely understand, but I don't think this is an issue. The generate_signal method can return multiple orders in the same iteration. So, if you wanted to update the SL of one trade, and open another trade at the same time, you could simply add both orders to the signal dict. For example:

# Construct first order
new_order = {'order_type': 'marktet',
             'direction': 1,
             'size': 10,
             'stop_loss': ...}

# Construct second, modify order
modify_order = {'order_type': 'modify',
                'related_orders': 12,
                'stop_loss': new_SL}

# Construct signal dict
signal_dict = {1: new_order,
               2: modify_order}

return signal_dict

Note that you can add as many orders to the signal dict as you like.

Does this address the issue you were referring to?

elijahho commented 2 years ago

Nice! Didn't realise generate_signal could return multiple orders. Thanks for the clarification!