Back

Support for one-cancels-the-other order (OCO )

I whipped this little gem up to help easily manage my Profit and Loss orders where when one or the other order is filled, the other is automatically canceled.

Still a little rough and could probably be improved or refactored to be more re-usable, but thought it might help as is.

Update Backtest








Hi there @Levitikon, I just saw your algorithm because this post.

Your implementation is great, thanks for sharing.

As I use only one open position at a time for any security, in order to close all submitted but not filled orders, I use the Liquidate method.

Check the logs in the attached backtest.

0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.


Hi @Levitikon,

It's working great + it helped me find and fix some annoying bugs.

Thank you very much for this wonderful gem.

0

Hi @ Levitikon and others,

Would anyone know why it seems to be triggering both the profit target and the stop loss at the same time in the following code:

In the code: I entering 1 order at a specific time I would like (8am).

Any idea why both are getting filled?

 

Thanks for the code!

 


namespace QuantConnect
{
public class indicator_res_test : QCAlgorithm
{
private OrderTicket EntryOrder { get; set; }
private Func<QCAlgorithm, string, decimal, OneCancelsOtherTicketSet> OnOrderFilledEvent { get; set; }
private OneCancelsOtherTicketSet ProfitLossOrders { get; set; }
public override void Initialize()
{
SetStartDate(2011, 6, 9);
SetEndDate(2011, 7, 1);
SetCash(10000);
AddSecurity(SecurityType.Forex, "EURUSD", Resolution.Minute, true, 50.0m, false);
}
public void OnData(TradeBars data)
{
if (!Portfolio.Invested && Time.TimeOfDay.Hours == 08)
{
this.OnOrderFilledEvent = (algo, symbol, filledPrice) =>
{
return new OneCancelsOtherTicketSet(
algo.LimitOrder(symbol, -45000, filledPrice + 0.00212m, "Profit Target"),
algo.StopMarketOrder(symbol, -45000, filledPrice - 0.00212m, "Stop Loss"));
};
this.EntryOrder = MarketOrder("EURUSD", 45000, false, "Entry");
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (EntryOrder != null)
{
this.EntryOrder = null;
}
if (orderEvent.Status == OrderStatus.Filled || orderEvent.Status == OrderStatus.PartiallyFilled)
{
if (this.OnOrderFilledEvent != null)
{
this.ProfitLossOrders = OnOrderFilledEvent(this, orderEvent.Symbol, orderEvent.FillPrice);
OnOrderFilledEvent = null;
}
else if (this.ProfitLossOrders != null)
{
this.ProfitLossOrders.Filled();
Log("Profit/Loss Filled" + "Portfolio Invested Check: =" + Portfolio.Invested);
this.ProfitLossOrders = null;
}
}
}
}
}

0


Hi Lucas,

Both orders are getting filled because both target and stop prices are getting hit in the same bar. Let me suggest some solutions:

-Increasing the resolution of the data to seconds will (in the great majority of cases) mean they're filled separately,

-Increasing the width of the stop and limit orders will also (in the great majority of cases) fix it.

-Keeping track of canceled order ids. If the order was successfully canceled an OrderEvent will be sent through the callback OnOrderEvent, with the corresponding OrderId and Status set as Canceled. If not, the Status will be Filled/PartiallyFilled, in which case you will want to liquidate the position.

0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.


Update Backtest





0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.


Loading...

This discussion is closed