Overall Statistics
Total Orders
2
Average Win
1.38%
Average Loss
0%
Compounding Annual Return
0.344%
Drawdown
1.400%
Expectancy
0
Start Equity
100000
End Equity
101382.34
Net Profit
1.382%
Sharpe Ratio
-0.798
Sortino Ratio
-0.441
Probabilistic Sharpe Ratio
5.627%
Loss Rate
0%
Win Rate
100%
Profit-Loss Ratio
0
Alpha
-0.009
Beta
0.029
Annual Standard Deviation
0.007
Annual Variance
0
Information Ratio
-0.96
Tracking Error
0.104
Treynor Ratio
-0.2
Total Fees
$2.00
Estimated Strategy Capacity
$2800000000.00
Lowest Capacity Asset
SPY R735QTJ8XC9X
Portfolio Turnover
0.02%
# region imports
from AlgorithmImports import *
# endregion

class FocusedApricotJackal(QCAlgorithm):
    '''Basic algorithm demonstrating how to place stop limit orders.'''

    Tolerance = 0.001
    FastPeriod = 30
    SlowPeriod = 60

    def Initialize(self):
        self.SetStartDate(2013, 1, 1)
        self.SetEndDate(2017, 1, 1)
        self.SetCash(100000)

        FastPeriod = self.GetParameter('ema-fast', 30)
        self._symbol = self.AddEquity("SPY", Resolution.Daily).Symbol

        self._fast = self.EMA(self._symbol, self.FastPeriod, Resolution.Daily)
        self._slow = self.EMA(self._symbol, self.SlowPeriod, Resolution.Daily)

        self._buyOrderTicket: OrderTicket = None
        self._sellOrderTicket: OrderTicket = None
        self._previousSlice: Slice = None

    def OnData(self, slice: Slice):
        if not self.IsReady():
            return

        security = self.Securities[self._symbol]
        if self._buyOrderTicket is None and self.TrendIsUp():
            self._buyOrderTicket = self.StopLimitOrder(self._symbol, 100, stopPrice=security.High * 1.10, limitPrice=security.High * 1.11)
        elif self._buyOrderTicket.Status == OrderStatus.Filled and self._sellOrderTicket is None and self.TrendIsDown():
            self._sellOrderTicket = self.StopLimitOrder(self._symbol, -100, stopPrice=security.Low * 0.99, limitPrice=security.Low * 0.98)

    def OnOrderEvent(self, orderEvent: OrderEvent):
        if orderEvent.Status == OrderStatus.Filled:
            order: StopLimitOrder = self.Transactions.GetOrderById(orderEvent.OrderId)
            if not order.StopTriggered:
                raise Exception("StopLimitOrder StopTriggered should haven been set if the order filled.")

            if orderEvent.Direction == OrderDirection.Buy:
                limitPrice = self._buyOrderTicket.Get(OrderField.LimitPrice)
                if orderEvent.FillPrice > limitPrice:
                    raise Exception(f"Buy stop limit order should have filled with price less than or equal to the limit price {limitPrice}. "
                                    f"Fill price: {orderEvent.FillPrice}")
            else:
                limitPrice = self._sellOrderTicket.Get(OrderField.LimitPrice)
                if orderEvent.FillPrice < limitPrice:
                    raise Exception(f"Sell stop limit order should have filled with price greater than or equal to the limit price {limitPrice}. "
                                    f"Fill price: {orderEvent.FillPrice}")

    def IsReady(self):
        return self._fast.IsReady and self._slow.IsReady

    def TrendIsUp(self):
        return self.IsReady() and self._fast.Current.Value > self._slow.Current.Value * (1 + self.Tolerance)

    def TrendIsDown(self):
        return self.IsReady() and self._fast.Current.Value < self._slow.Current.Value * (1 + self.Tolerance)