| 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