Overall Statistics
Total Trades
2
Average Win
1.72%
Average Loss
0%
Compounding Annual Return
21.317%
Drawdown
0.300%
Expectancy
0
Net Profit
1.720%
Sharpe Ratio
6.985
Loss Rate
0%
Win Rate
100%
Profit-Loss Ratio
0
Alpha
0.225
Beta
-0.07
Annual Standard Deviation
0.027
Annual Variance
0.001
Information Ratio
-3.371
Tracking Error
0.106
Treynor Ratio
-2.688
Total Fees
$2.00
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Algorithm;
using QuantConnect.Data.Market;
using QuantConnect.Orders;

namespace QuantConnect
{
    public class OneCancelsAllAlgorithm : QCAlgorithm
    {
        public const string Symbol = "SPY";
        // we need a concurrent data structure since we're using it in both OnData and OnOrderEvent which run on separate t
        public readonly ConcurrentBag<OneCancelsAll> orderGroups = new ConcurrentBag<OneCancelsAll>();

        //Initialize the data and resolution you require for your strategy:
        public override void Initialize()
        {
            //Start and End Date range for the backtest:
            SetStartDate(2013, 01, 1);
            SetEndDate(2013, 02, 01);

            //Cash allocation
            SetCash(25000);

            //Add as many securities as you like. All the data will be passed into the event handler:
            AddSecurity(SecurityType.Equity, Symbol, Resolution.Daily);
        }

        //Data Event Handler: New data arrives here. "TradeBars" type is a dictionary of strings so you can access it by symbol.
        public void OnData(TradeBars data)
        {
            if (Transactions.OrdersCount == 0)
            {
                // open an initial position
                MarketOrder(Symbol, 100);

                var oca = new OneCancelsAll();
                // set profit taking order
                var limitPrice = data[Symbol].Close * 1.05m;
                var profitTakingTicket = LimitOrder(Symbol, -100, limitPrice, tag: "TakeProfit: " + limitPrice);
                // set stop loss order
                var stopPrice = data[Symbol].Low * .99m;
                var stopLossTicket = StopMarketOrder(Symbol, -100, stopPrice, tag: "StopLoss: " + stopPrice);

                // add tickets to our oca group
                oca.Tickets.Add(profitTakingTicket);
                oca.Tickets.Add(stopLossTicket);
                orderGroups.Add(oca);
            }
        }

        public override void OnOrderEvent(OrderEvent fill)
        {
            Console.WriteLine(Time + ": " + Transactions.GetOrderById(fill.OrderId).Type + ": " + fill);
            if (fill.Status.IsClosed())
            {
                // find the oca grouping from this fill
                foreach (var oca in orderGroups)
                {
                    // check if this oca matches the fill we received
                    if (oca.Tickets.Any(x => x.OrderId == fill.OrderId))
                    {
                        // cancel all orders that aren't this order id
                        foreach (var ticket in oca.Tickets)
                        {
                            // cancel each other ticket in our OCA group
                            if (ticket.OrderId != fill.OrderId && ticket.Status.IsOpen())
                            {
                                ticket.Cancel();
                                Log("Cancelled OCA: " + ticket.OrderId + " tag: " + ticket.Tag);
                            }
                        }
                    }
                }
            }
        }
    }
    // class to hold ticks in an OCA group
    public class OneCancelsAll
    {
        public List<OrderTicket> Tickets = new List<OrderTicket>();
    }
}