Ордер Sellstop не исполняется, если сделка на покупку уже открытаPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Ордер Sellstop не исполняется, если сделка на покупку уже открыта

Сообщение Anonymous »

Я провел два теста, которые четко объясняют сценарий. См. блок кода notify_order и notify_trade ниже.
**Тест 1 (выполнение только 1 ордера SellStop):
**
Когда я исполняю только ордер SellStop, я получаю то, что ожидалось.
В моем notify_order я получаю журналы о том, что мой ордер на продажу ОТПРАВЛЕН и ПРИНЯТ (еще не ЗАВЕРШЕН, поскольку цена еще не достигла цены SellStop).
Когда цена достигает триггерной цены для SellStop ордера, я получаю в своем notify_order журналы о том, что мой ордер на продажу ЗАВЕРШЕН, и сразу после этого я получаю регистрирует в моем notify_trade, что была исполнена сделка на продажу (для отслеживания этого я использую trade.justopened).
**Тест 2 (выполнение 1 сделки на покупку) и 1 ордер Sellstop):
**
Когда я открываю сделку на покупку (которая исполняется немедленно) и ордер Sellstop, у меня возникают проблемы.
Я получаю журналы мой notify_order о том, что моя сделка на покупку ОТПРАВЛЕНА, ПРИНЯТА и ЗАВЕРШЕНА, и в моем notify_trade я получаю журналы о том, что сделка на покупку успешно выполнена. Как и выше в тесте 1, я получаю журналы в моем notify_order одновременно со сделкой на покупку, когда мой ордер на продажу ОТПРАВЛЯЕТСЯ и ПРИНИМАЕТСЯ (но еще не ЗАВЕРШЕН, поскольку цена еще не достигла цены стопа продажи). ).
Когда цена достигает триггерной цены для ордера SellStop, я все равно получаю журналы в моем notify_order о том, что мой ордер на продажу ЗАВЕРШЕН, но теперь я не получаю журналов в своем notify_trade. В тесте 2 не ожидается никаких изменений кода для добавления сделки на покупку.
ПРИМЕЧАНИЕ. Когда вы делаете то же самое с лимитными ордерами, все работает нормально (лимитные ордера также являются отложенными ордерами, как и стоп-ордера). ). Странно, что это происходит только со стоп-ордерами на продажу.
Публиковал ли Backtrader какие-либо вопросы и ответы по поводу этих проблем с ордерами? Или у кого-нибудь есть решение?

Код: Выделить всё

def notify_order(self, order):
"""
ORDERS are actions that are unfulfilled/pending
(means they are waiting to enter or be triggered into the market)
Args:
order: order.status can be any of {order.Created, order.Submitted,
order.Accepted, order.Partial,
order.Completed, order.Canceled, order.Expired, order.Margin, order.Rejected}
#todo type hint

Returns: None
"""

if order.status in [order.Submitted]:
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- Order {order.ref} Submitted at price {order.price}, commission {order.executed.comm}\n{order}')

if order.p.exectype == 0 : # Market order
if order.isbuy():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of BUY type Ref ID {order.ref} SUBMITTED at Price: {order.price}, commission {order.executed.comm}')
elif order.issell():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of SELL type Ref ID {order.ref} SUBMITTED at Price: {order.price}, commission {order.executed.comm}')
else:
pass

elif order.p.exectype == 2 : # Limit order
if order.isbuy():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of BUY type Ref ID {order.ref} SUBMITTED at Price: {order.price}, commission {order.executed.comm}')
elif order.issell():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of SELL type Ref ID {order.ref} SUBMITTED at Price: {order.price}, commission {order.executed.comm}')
else:
pass

elif order.p.exectype == 3 : # Stop order
if order.isbuy():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of BUY type Ref ID {order.ref} SUBMITTED at Price: {order.price}, commission {order.executed.comm}')
elif order.issell():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of SELL type Ref ID {order.ref} SUBMITTED at Price: {order.price}, commission {order.executed.comm}')
else:
pass
else:
pass
return

if order.status in [order.Accepted]:
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- Order {order.ref} Accepted at price {order.price}, commission {order.executed.comm}\n{order}')

if order.p.exectype == 0 : # Market order
if order.isbuy():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of BUY type Ref ID {order.ref} ACCEPTED at Price: {order.price}, commission {order.executed.comm}')
elif order.issell():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of SELL type Ref ID {order.ref} ACCEPTED at Price: {order.price}, commission {order.executed.comm}')
else:
pass

elif order.p.exectype == 2 : # Limit order
if order.isbuy():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of BUY type Ref ID {order.ref} ACCEPTED at Price: {order.price}, commission {order.executed.comm}')
elif order.issell():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of SELL type Ref ID {order.ref} ACCEPTED at Price: {order.price}, commission {order.executed.comm}')
else:
pass

elif order.p.exectype == 3 : # Stop order
if order.isbuy():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of BUY type Ref ID {order.ref} ACCEPTED at Price: {order.price}, commission {order.executed.comm}')
elif order.issell():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of SELL type Ref ID {order.ref} ACCEPTED at Price:  {order.price}, commission {order.executed.comm}')
else:
pass
else:
pass
return

if order.status in [order.Completed]:
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- Order {order.ref} Completed at price {order.price}, commission {order.executed.comm}\n{order}')

if order.p.exectype == 0 : # Market order
if order.isbuy():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of BUY type Ref ID {order.ref} COMPLETED at Price: {order.price}, commission {order.executed.comm}')
elif order.issell():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of SELL type Ref ID {order.ref} COMPLETED at Price: {order.price}, commission {order.executed.comm}')
else:
pass

elif order.p.exectype == 2 : # Limit order
if order.isbuy():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of BUY type Ref ID {order.ref} COMPLETED at Price: {order.price}, commission {order.executed.comm}')
elif order.issell():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of SELL type Ref ID {order.ref} COMPLETED at Price: {order.price}, commission {order.executed.comm}')
else:
pass

elif order.p.exectype == 3 : # Stop order
if order.isbuy():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of BUY type Ref ID {order.ref} COMPLETED at Price: {order.price}, commission {order.executed.comm}')
elif order.issell():
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of SELL type Ref ID {order.ref} COMPLETED at Price: {order.price}, commission {order.executed.comm}')
else:
pass
else:
pass
return

if order.status in [order.Canceled]:
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- Order {order.ref} Canceled.  Specs of order:\n{order}')

if order.isbuy():
if order.p.exectype == 0:
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of BUY type ID {order.info.ref} & Ref ID {order.ref} deleted')
elif order.p.exectype == 2:
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of BUY type ID {order.info.ref} & Ref ID {order.ref} deleted')
elif order.p.exectype == 3:
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of BUY type ID {order.info.ref} & Ref ID {order.ref} deleted')
else:
pass

elif order.issell():
if order.p.exectype == 0:
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- MARKET order of SELL type ID {order.info.ref} & Ref ID {order.ref} deleted')
elif order.p.exectype == 2:
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- LIMIT order of SELL type ID {order.info.ref} & Ref ID {order.ref} deleted')
elif order.p.exectype == 3:
log.debug(f'{self.datetime.datetime(ago=0).isoformat()} --- STOP order of SELL type ID {order.info.ref} & Ref ID {order.ref} deleted')
else:
pass

if order.status in [order.Expired]:
log.info(f'{self.datetime.datetime(ago=0).isoformat()}  --- Order {order.ref} Expired and could not be executed')
self.remove_open_order(order.p.tradeid)
return

if order.status in [order.Margin]:
log.error(f'{self.datetime.datetime(ago=0).isoformat()}  --- Insufficient cash to execute order - increase starting cash or improve strategy: Order {order.ref} Margin')
# log.error(f'{self.datetime.datetime(ago=0).isoformat()}  --- Current balance {self.broker.getcash()} and equity {self.broker.getvalue()} - trying to open order {order.ref} with size {}')
self.cerebro.runstop()
return

if order.status in [order.Rejected]:
log.info(f'{self.datetime.datetime(ago=0).isoformat()}  --- Order {order.ref} Rejected by broker and could not be executed')
self.remove_open_order(order.p.tradeid)
return

def notify_trade(self, trade):
"""
TRADES are actions that are fulfilled
(means they are active - in a trade and making/losing money)
"""
if trade.justopened:

# commission added when trade is opened (entry commission) and closed (exit commission)
self.strategy.total_commission += trade.commission # calculating total commission paid
# self.open_orders[trade.tradeid]['commission'] = trade.commission # assign commission of orders in open_orders dict

try:
if self.open_orders[trade.tradeid]['action'] == 'buy':
log.debug(f"{self.datetime.datetime(ago=0).isoformat()} --- BUY trade ID {trade.tradeid} executed at price {trade.price}")

# assign the actual executed entry price to the backtrader buy object
self.buy_trade[trade.tradeid][0].price = trade.price

# assign the actual executed entry price to initially opened buy trades; note that modification trades need to be tracked seperately
if trade.tradeid not in self.modification_list:
self.strategy.total_long_orders += 1
self.open_orders[trade.tradeid]['price'] = trade.price

elif self.open_orders[trade.tradeid]['action'] == 'sell':
log.debug(f"{self.datetime.datetime(ago=0).isoformat()} --- SELL trade ID {trade.tradeid} executed at price {trade.price}")

# assign the actual executed entry price to the backtrader sell object
self.sell_trade[trade.tradeid][0].price = trade.price

# assign the actual executed entry price to initially opened sell trades; note that modification trades need to be tracked seperately
if trade.tradeid not in self.modification_list:
self.strategy.total_short_orders += 1
self.open_orders[trade.tradeid]['price'] = trade.price

elif self.open_orders[trade.tradeid]['action'] == 'buylimit':
log.debug(f"{self.datetime.datetime(ago=0).isoformat()} --- BUYLIMIT {self.buy_limit[trade.tradeid][0].ref} ->  BUY TRADE ID {trade.tradeid}")
self.open_orders[trade.tradeid]['action'] = 'buy'
# assign the actual executed entry price to the backtrader buy object when a buylimit becomes a buy
self.open_orders[trade.tradeid]['price'] = trade.price
self.buy_trade[trade.tradeid] = self.buy_limit[trade.tradeid] # move buylimit objects to buy objects
del self.buy_limit[trade.tradeid] # removing the buylimit objects as it became a buy trade

elif self.open_orders[trade.tradeid]['action'] == 'buystop':
log.debug(f"{self.datetime.datetime(ago=0).isoformat()} --- BUYSTOP {self.buy_stop[trade.tradeid][0].ref} -> BUY TRADE ID {trade.tradeid}")
self.open_orders[trade.tradeid]['action'] = 'buy'
# assign the actual executed entry price to the backtrader buy object when a buystop becomes a buy
self.open_orders[trade.tradeid]['price'] = trade.price
self.buy_trade[trade.tradeid] = self.buy_stop[trade.tradeid] # move buystop objects to buy objects
del self.buy_stop[trade.tradeid] # removing the buystop objects as it became a buy trade

elif self.open_orders[trade.tradeid]['action'] == 'selllimit':
log.debug(f"{self.datetime.datetime(ago=0).isoformat()} --- SELLLIMIT {self.sell_limit[trade.tradeid][0].ref} -> SELL TRADE ID {trade.tradeid}")
self.open_orders[trade.tradeid]['action'] = 'sell'
# assign the actual executed entry price to the backtrader buy object when a selllimit becomes a sell
self.open_orders[trade.tradeid]['price'] = trade.price
self.sell_trade[trade.tradeid] = self.sell_limit[trade.tradeid] # move selllimit objects to sell objects
del self.sell_limit[trade.tradeid] # removing the selllimit objects as it became a sell trade

elif self.open_orders[trade.tradeid]['action'] == 'sellstop':
log.debug(f"{self.datetime.datetime(ago=0).isoformat()} --- SELLSTOP {self.sell_stop[trade.tradeid][0].ref} -> SELL TRADE ID {trade.tradeid}")
self.open_orders[trade.tradeid]['action'] = 'sell'
# assign the actual executed entry price to the backtrader buy object when a sellstop becomes a sell
self.open_orders[trade.tradeid]['price'] = trade.price
self.sell_trade[trade.tradeid] = self.sell_stop[trade.tradeid] # move sellstop objects to sell objects
del self.sell_stop[trade.tradeid] # removing the sellstop objects as it became a sell trade
else:
pass
except KeyError:
pass
else:
pass
log.debug(f"{self.datetime.date(ago=0).isoformat()} {self.datetime.time(ago=0).isoformat()} --- TRADE ID {trade.tradeid} with ENTRY PRICE {trade.price} CLOSED, final PNL {trade.pnl} & NET PROFIT {trade.pnlcomm}")

Я провел несколько тестов и пришел к выводу, что тест 1 и тест 2 хорошо определяют проблему.
В тесте 1 я доказываю, что ордера на продажу корректно выполняются Backtrader. В тесте 2 я доказываю, что добавление к ситуации одной сделки на покупку приводит к неправильному исполнению ордеров на продажу Backtrader

Подробнее здесь: https://stackoverflow.com/questions/792 ... ready-open
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»