Overall Statistics
Total Trades
14
Average Win
5.01%
Average Loss
0%
Compounding Annual Return
41.264%
Drawdown
4.000%
Expectancy
0
Net Profit
41.398%
Sharpe Ratio
3.14
Probabilistic Sharpe Ratio
98.906%
Loss Rate
0%
Win Rate
100%
Profit-Loss Ratio
0
Alpha
0.255
Beta
0.122
Annual Standard Deviation
0.088
Annual Variance
0.008
Information Ratio
0.417
Tracking Error
0.257
Treynor Ratio
2.262
Total Fees
$14.00
Estimated Strategy Capacity
$480000000.00
Lowest Capacity Asset
SPY R735QTJ8XC9X
Portfolio Turnover
3.83%
# region imports
from AlgorithmImports import *
# endregion

class WellDressedLightBrownDolphin(QCAlgorithm):

    def Initialize(self):
        # self referenced the QCAlgorithm class
        self.SetStartDate(2020, 1, 1)  # Set Start Date for back test
        self.SetEndDate(2021, 1, 1)  # Set End Date for back test otherwise most recent date is chosen
        self.SetCash(25000)  # Set Strategy Cash

        # Resolution is the timeframe for this ticker
        equity = self.AddEquity("SPY", Resolution.Daily, )
        equity.SetDataNormalizationMode(DataNormalizationMode.Raw)

        # self.spy is an instance variable due to 'self'
        self.spy = equity.Symbol
        
        self.SetBenchmark("SPY")
        # Cash accounts no leverage, Margin allows leverage
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)

        # helper variables to track entry price
        self.entryPrice = 0
        # timedelta (from datetime library) object represents a duration, the difference between two dates or times.
        self.period = timedelta(days = 31) 
        self.nextEntryTime = self.Time # current time frontier QCA

    def OnData(self, data: Slice):
        # check if there is data in the Slice object dictionary for the symbol 
        if not self.spy in data:
            return
        
        # below multiple ways to get the price based on the dictionaries of various classes in data Slice object
        # price = data.Bars[self.spy].Close
        # price = self.Securities[self.spy].Close
        price = data[self.spy].Close
        self.Debug("{0} Close is: {1}".format(self.spy ,price))

        if not self.Portfolio.Invested:
            
            # check if nextEntryTime smaller dan current time frontier
            # if true means the current time has passed the nextEntryTime, the algo may buy
            if self.nextEntryTime <= self.Time:
                
                # self.MarketOrder(self.spy, int(self.PortfolioCash / price))
                # SetHoldings beter way, because of auto calculation. 1 = 100% buy, -1=100% sell
                self.SetHoldings(symbol=self.spy, percentage=1)               
                self.Log(f"BUY SPY @{price}")
                # save entryPrice to know when to exit
                self.entryPrice = price

        # if 10% profit or -10% loss then exit by liquidating
        elif self.entryPrice * 1.05 < price or self.entryPrice * 0.9 > price:
            
            #self.Liquidate(self.spy)
            # liquidates all positions in your portfolio
            self.Liquidate()
            self.Log(f"SELL SPY @{price}")
            # bot can trade again after 31 days
            self.nextEntryTime = self.Time + self.period