Comments (21)
ok, will look into this later.
from btoandav20.
Then your order is still pending. You will receive completed once the order is executed by oanda.
from btoandav20.
I am saying what I am seeing is that the order is completed, as in I see it go through on the Oanda dashboard/TradingView, but I never receive the notification in backtrader.
from btoandav20.
the order is entered (it appears in oanda) but did it execute? like did it open a position?
from btoandav20.
Yes the orders execute as in there was an open position and I won/lost money, haha.
For example:
self.E1 = self.buy(price=entry_price, size=size, exectype=bt.Order.Stop, transmit=False)
self.SL1 = self.sell(price=stoploss_price, size=size, exectype=bt.Order.Stop, transmit=False, parent=self.E1)
self.TP1 = self.sell(price=TP1_price, size=size, exectype=bt.Order.Limit, transmit=True, parent=self.E1)
E1 is Submitted -> Accepted
E1 is hit and it opens a new position (but no Completed
)
TP1 is hit and won money (but no Completed
)
from btoandav20.
could you provide some sample code which shows the problem
from btoandav20.
Goal is to try to move SL2 to breakeven after TP1 is hit. I am logging out every order notification in the beginning and it never seems to print Completed
, so order.status == order.Completed
logic never executes.
def notify_order(self, order):
logs = True
logs and print('{}: Order ref: {} / Type {} / Status {} / ExecType {} / Size {} / Alive {} / Price {} / Position {}'.format(
self.data.datetime.date(0),
order.ref,
'Buy' * order.isbuy() or 'Sell',
order.getstatusname(),
order_exectypes[order.exectype],
order.size,
order.alive(),
order.executed.price,
self.position.size,
))
if order.alive():
# Submitted, Accepted, Partial
if order.status in (order.Partial, order.Submitted):
# otherwise these ^ get stuck sometimes
if self.E1 and order.ref == self.E1.ref: self.E1 = None
elif self.E2 and order.ref == self.E2.ref: self.E2 = None
# pass
else:
# Completed, Canceled, Rejected
if self.E1 and order.ref == self.E1.ref: self.E1 = None
elif self.SL1 and order.ref == self.SL1.ref: self.SL1 = None
elif self.TP1 and order.ref == self.TP1.ref:
self.TP1 = None
if self.params.breakeven:
if order.status == order.Completed:
logs and print('HIT TP1')
if self.SL2 and self.last_entry_price:
# if hit TP1, move SL2 to breakeven
logs and print('MOVE SL2 TO BREAKEVEN', self.last_entry_price)
self.move_stop_loss(self.last_entry_price)
self.last_entry_price = None
elif self.E2 and order.ref == self.E2.ref:
self.E2 = None
if self.params.breakeven:
if order.status == order.Completed:
self.last_entry_price = order.executed.price
elif self.SL2 and order.ref == self.SL2.ref:
self.SL2 = None
if self.params.breakeven:
if order.status == order.Completed:
logs and print('CREATED NEW SL2')
# only when the new SL2 gets successfully created, then can we cancel the old one
if self.old_SL2:
logs and print('CANCEL OLD SL2')
self.old_SL2.cancel()
self.old_SL2 = None
elif self.TP2 and order.ref == self.TP2.ref:
self.TP2 = None
if self.params.breakeven:
if order.status == order.Completed:
logs and print('HIT TP2')
# if SL2 was moved to breakeven after TP1, and therefore it is not of the original transmit group, then we now need to manually cancel it after TP2 is hit
if self.SL2 and self.moved_SL2:
logs and print('CANCEL NEW SL2')
self.SL2.cancel()
self.moved_SL2 = False
from btoandav20.
Goal is to try to move SL2 to breakeven after TP1 is hit. I am logging out every order notification in the beginning and it never seems to get
Completed
, soorder.status == order.Completed
logic never executes.def notify_order(self, order): logs = True logs and print('{}: Order ref: {} / Type {} / Status {} / ExecType {} / Size {} / Alive {} / Price {} / Position {}'.format( self.data.datetime.date(0), order.ref, 'Buy' * order.isbuy() or 'Sell', order.getstatusname(), order_exectypes[order.exectype], order.size, order.alive(), order.executed.price, self.position.size, )) if order.alive(): # Submitted, Accepted, Partial if order.status in (order.Partial, order.Submitted): # otherwise these ^ get stuck sometimes if self.E1 and order.ref == self.E1.ref: self.E1 = None elif self.E2 and order.ref == self.E2.ref: self.E2 = None # pass else: # Completed, Canceled, Rejected if self.E1 and order.ref == self.E1.ref: self.E1 = None elif self.SL1 and order.ref == self.SL1.ref: self.SL1 = None elif self.TP1 and order.ref == self.TP1.ref: self.TP1 = None if self.params.breakeven: if order.status == order.Completed: logs and print('HIT TP1') if self.SL2 and self.last_entry_price: # if hit TP1, move SL2 to breakeven logs and print('MOVE SL2 TO BREAKEVEN', self.last_entry_price) self.move_stop_loss(self.last_entry_price) self.last_entry_price = None elif self.E2 and order.ref == self.E2.ref: self.E2 = None if self.params.breakeven: if order.status == order.Completed: self.last_entry_price = order.executed.price elif self.SL2 and order.ref == self.SL2.ref: self.SL2 = None if self.params.breakeven: if order.status == order.Completed: logs and print('CREATED NEW SL2') # only when the new SL2 gets successfully created, then can we cancel the old one if self.old_SL2: logs and print('CANCEL OLD SL2') self.old_SL2.cancel() self.old_SL2 = None elif self.TP2 and order.ref == self.TP2.ref: self.TP2 = None if self.params.breakeven: if order.status == order.Completed: logs and print('HIT TP2') # if SL2 was moved to breakeven after TP1, and therefore it is not of the original transmit group, then we now need to manually cancel it after TP2 is hit if self.SL2 and self.moved_SL2: logs and print('CANCEL NEW SL2') self.SL2.cancel() self.moved_SL2 = False
please post how you create the orders.
from btoandav20.
def buy_risk(self):
stop_dist = self.set_stop_dist()
entry_dist = self.set_entry_dist()
entry_price = self.last5high[0] + entry_dist
stoploss_price = self.l[0] - stop_dist
R = entry_price - stoploss_price
R_pips_big = R * 10000
TP1_price = entry_price + (1 * R)
TP2_price = entry_price + (2 * R)
size = self.calculate_risk_size(R_pips_big)
print('SL %.4f / Price %.4f / BuyStop %.4f / R=%.4f %.4f / TP1=%.4f / TP2=%.4f / size %.4f / Stop Dist %.4f' % (
stoploss_price,
self.c[0],
entry_price,
R, R_pips_big,
TP1_price,
TP2_price,
size,
stop_dist,
))
self.E1 = self.buy(price=entry_price, size=size, exectype=bt.Order.Stop, transmit=False)
self.SL1 = self.sell(price=stoploss_price, size=size, exectype=bt.Order.Stop, transmit=False, parent=self.E1)
self.TP1 = self.sell(price=TP1_price, size=size, exectype=bt.Order.Limit, transmit=True, parent=self.E1)
self.E2 = self.buy(price=entry_price, size=size, exectype=bt.Order.Stop, transmit=False)
self.SL2 = self.sell(price=stoploss_price, size=size, exectype=bt.Order.Stop, transmit=False, parent=self.E2)
self.TP2 = self.sell(price=TP2_price, size=size, exectype=bt.Order.Limit, transmit=True, parent=self.E2)
from btoandav20.
for now you could try if bracket orders will work with your code
from btoandav20.
I could not really replicate your issue. I entered these values for the orders:
self.E1 = self.buy(price=self.data.close[0], size=100, exectype=bt.Order.Stop, transmit=False)
self.SL1 = self.sell(price=self.data.close[0] + 0.0005, size=100, exectype=bt.Order.Stop, transmit=False, parent=self.E1)
self.TP1 = self.sell(price=self.data.close[0] - 0.0002, size=100, exectype=bt.Order.Limit, transmit=True, parent=self.E1)
but these orders get canceled. you can use the code at the bottom to provide a strategy which replicates your issue.
from __future__ import (absolute_import, division, print_function,
unicode_literals)
# For datetime objects
import datetime
import pytz
# Import the backtrader platform
import backtrader as bt
import btoandav20 as bto
import backtrader.version as btvers
print(btvers.__version__)
class strategy(bt.Strategy):
'''Initialization '''
def __init__(self):
self.live = True
def log(self, txt, dt=None):
dt = dt or self.data.datetime.datetime(0)
print('%s, %s' % (dt.isoformat(), txt))
''' Store notification '''
def notify_store(self, msg, *args, **kwargs):
print('-' * 50, 'STORE BEGIN', datetime.datetime.now())
print(msg)
print('-' * 50, 'STORE END')
''' Order notification '''
def notify_order(self, order):
if order.status in [order.Completed, order.Cancelled, order.Rejected]:
self.order = None
print('-' * 50, 'ORDER BEGIN', datetime.datetime.now())
print(order)
print('-' * 50, 'ORDER END')
''' Trade notification '''
def notify_trade(self, trade):
print('-' * 50, 'TRADE BEGIN', datetime.datetime.now())
print(trade)
print('-' * 50, 'TRADE END')
if not trade.isclosed:
return
self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
(trade.pnl, trade.pnlcomm))
''' Data notification '''
def notify_data(self, data, status, *args, **kwargs):
print('*' * 5, 'DATA NOTIF:', data._getstatusname(status), *args)
if status == data.LIVE:
self.live = True
elif status == data.DELAYED:
self.live = False
def next(self):
self.log('Next {}, {} {} {} {}'.format(len(self.data), self.data.open[0], self.data.high[0], self.data.low[0], self.data.close[0]))
print(self.position)
if not self.position and self.live:
self.E1 = self.buy(price=self.data.close[0], size=100, exectype=bt.Order.Stop, transmit=False)
self.SL1 = self.sell(price=self.data.close[0] + 0.0005, size=100, exectype=bt.Order.Stop, transmit=False, parent=self.E1)
self.TP1 = self.sell(price=self.data.close[0] - 0.0002, size=100, exectype=bt.Order.Limit, transmit=True, parent=self.E1)
elif self.live:
#self.close()
pass
# Create a cerebro entity
cerebro = bt.Cerebro(quicknotify=True)
# Prepare oanda STORE
storekwargs = dict(
token="",
account="",
practice=True,
)
print(bto.stores)
store = bto.stores.OandaV20Store(**storekwargs)
# Prepare oanda data
datakwargs = dict(
timeframe=bt.TimeFrame.Seconds,
compression=5,
tz=pytz.timezone('Europe/Berlin'),
backfill=False,
backfill_start=False,
)
data = store.getdata(dataname="EUR_USD", **datakwargs)
#data.resample(timeframe=bt.TimeFrame.Seconds, compression=30,rightedge=True,boundoff=1)
cerebro.adddata(data)
# Add broker
cerebro.setbroker(store.getbroker())
# Add strategy
cerebro.addstrategy(strategy)
cerebro.run()
from btoandav20.
Also please Check if the both stop orders (one with entry price) are really stop orders or if the first one should be a limit order.
from btoandav20.
Hi if you did:
self.E1 = self.buy(price=self.data.close[0], size=100, exectype=bt.Order.Stop, transmit=False)
self.SL1 = self.sell(price=self.data.close[0] + 0.0005, size=100, exectype=bt.Order.Stop, transmit=False, parent=self.E1)
self.TP1 = self.sell(price=self.data.close[0] - 0.0002, size=100, exectype=bt.Order.Limit, transmit=True, parent=self.E1)
It is a Buy
position, so SL1
stop loss should be below, TP1
take profit should be above. So maybe just:
self.E1 = self.buy(price=self.data.close[0] + 0.0005, size=100, exectype=bt.Order.Stop, transmit=False)
self.SL1 = self.sell(price=self.data.close[0] - 0.0005, size=100, exectype=bt.Order.Stop, transmit=False, parent=self.E1)
self.TP1 = self.sell(price=self.data.close[0] + 0.0010, size=100, exectype=bt.Order.Limit, transmit=True, parent=self.E1)
And yes, it should be:
- Entry: Buy Stop (to buy when price goes up and hits the price)
- Stop Loss: Sell Stop (below)
- Take Profit: Sell Limit (above)
But from what I have seen, it doesn't matter what the order type is, I never see Completed
status when running live even with regular Market order instead of Stop order e.g. self.E1 = self.buy(size=100, exectype=bt.Order.Market, transmit=False)
.
from btoandav20.
I am not really sure, how to send this type of orders. When sending your orders, oanda will reject it with CLIENT_ORDER_ID_ALREADY_EXISTS
from btoandav20.
i committed some changes today, you can check them out. you will get better error codes and descriptions for further investigation. the issue seems to be that either the stores creates the stop order wrong or there is an other issue.
CLIENT_ORDER_ID_ALREADY_EXISTS: The client Order ID specified is already assigned to another pending Order
these are the generated order details:
{'instrument': 'EUR_USD',
'units': 100,
'type': 'STOP',
'price': '1.11979',
'timeInForce': 'GTC',
'stopLossOnFill': {'price': '1.11879', 'timeInForce': 'GTC', 'clientExtensions': {'id': '2'}},
'takeProfitOnFill': {'price': '1.12029', 'timeInForce': 'GTC', 'clientExtensions': {'id': '3'}},
'clientExtensions': {'id': '1'}}
the clientExtensions id is the id of the order in backtrader.
you can check out https://developer.oanda.com/rest-live-v20/transaction-df/ for the needed details for the type of orders you would like to submit.
from btoandav20.
Would need a better explanation of what you want to achieve. Will wait for more details.
from btoandav20.
Thanks, I appreciate you exposing the errors! Ok, I will look into this more. Yes, I've been struggling so much with the manual brackets that I just switched to Market orders, and it turns out my algorithm actually performs better...
I heard back from Oanda support. They said what you said:
1) Transaction no.: 40749
Reason for Stop Order Reject: TRAILING_STOP_LOSS_ON_FILL_PRICE_DISTANCE_MINIMUM_NOT_MET
*Please note that Trailing Stop must be at least 5 pips away however you had it at 3 pips away. Hence, it was rejected
2) Transaction no.: 40748, 40747
Reason for Stop Order Reject: CLIENT_ORDER_ID_ALREADY_EXISTS
*Wet cannot create a new Stop order using an order ID that already exists from past orders. Please use a new order ID. (e.g Transaction #: 40747: You are trying to create a Stop order with ID 25 but the order ID 25 already exists from past transaction.).
As for more explanation/details, was basically just trying to do the risk management strategy as shown here: https://youtu.be/zhEukjCzXwM?t=747
from btoandav20.
we could ensure, that the id is unique, so adding some unique key for id, which changes when you restart the script
from btoandav20.
As for more explanation/details, was basically just trying to do the risk management strategy as shown here: https://youtu.be/zhEukjCzXwM?t=747
for that, you could achieve this by setting limit orders in opposite direction. you would need to cancel the order once you would set a new order when the price reaches new high (or low).
from btoandav20.
added a unique client id, now you will not get CLIENT_ORDER_ID_ALREADY_EXISTS messages, for the other issues, Stop orders work, will close this issue.
from btoandav20.
@ booboothefool
I did not fully go through your post here, but today I will open an issue but you can check my code, I think it is something along the lines of what u want to do.
from btoandav20.
Related Issues (20)
- cannot connect HOT 1
- OANDA v20 repetitive disconnection HOT 6
- Issue in oandav20store.py line 879 for Python3 HOT 3
- Simple backtest example HOT 9
- Timing out and not reconnecting HOT 9
- Timezone, Live Data and Connection Timeouts HOT 1
- Order replacement for bracket orders
- Is this msg_type check necessary? HOT 11
- Live Feed constantly dropping out HOT 1
- StopLimit returns rejected HOT 2
- Not consistence parameter stoploss & pips name in getsizing function HOT 1
- Datafeeds delay candle when set node candles=True HOT 3
- The sizers don't work as my expection HOT 1
- Why no loop when call response =??? HOT 2
- 401 (Unauthorized) on btoandav20 works ok on oandapyV20 HOT 1
- Need your help or explain because backtrader stops after receiving new data at new minute HOT 4
- the status of expired order is still "Accepted" in living trading HOT 1
- Commission HOT 1
- Is this expected `broker.getcash()` behavior? HOT 2
- Makes Orders during the backfill candles
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from btoandav20.