| Overall Statistics |
|
Total Trades 45 Average Win 1.79% Average Loss -4.72% Compounding Annual Return -86.797% Drawdown 57.700% Expectancy -0.803 Net Profit -45.056% Sharpe Ratio -1.023 Probabilistic Sharpe Ratio 2.777% Loss Rate 86% Win Rate 14% Profit-Loss Ratio 0.38 Alpha -0.963 Beta -2.217 Annual Standard Deviation 0.675 Annual Variance 0.455 Information Ratio -0.723 Tracking Error 0.785 Treynor Ratio 0.311 Total Fees $45.00 Estimated Strategy Capacity $18000000.00 Lowest Capacity Asset TZA U7EC123NWZTX |
import clr
clr.AddReference("System")
clr.AddReference("QuantConnect.Algorithm")
clr.AddReference("QuantConnect.Indicators")
clr.AddReference("QuantConnect.Common")
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
class QuantumCalibratedComputer(QCAlgorithm):
def Initialize(self):
self.SetTimeZone("America/New_York")
self.SetBenchmark('SPY')
self.SetStartDate(2022, 1, 1) #Set Start Date
self.SetEndDate(2022, 4, 19) #Set End Date
self.SetCash(2400) #Set Strategy Cash
# https://github.com/QuantConnect/Lean/blob/master/Algorithm.Framework/Risk/TrailingStopRiskManagementModel.py
self.SetRiskManagement(TrailingStopRiskManagementModel(0.25))
# atr_number = int(self.GetParameter('atr_number'))
# pl_stop = float(self.GetParameter('pl_stop'))
# breakout = int(self.GetParameter('breakout'))
# slow, fast = int(self.GetParameter('slow_ma')), int(self.GetParameter('fast_ma'))
self.symbols = {
# 0symbol, 1per time, 2max_pos, 3atr_number, 4pl_stop, 5breakout
# 6slow, 7fast, 8take_profit, 9 trailing_stop_price
# 'psq': ['PSQ', 50, 100, 1.5, -0.03, 5, 120, 60, 0.3, None],
# 'slv': ['SLV', 50, 100, 1.5, -0.03, 10, 120, 30, 0.3, None],
# 'rwm': ['RWM', 50, 100, 1.5, -0.03, 5, 120, 60, 0.3, None],
'tza': ['TZA', 15, 45, 1.5, -0.1, 5, 120, 60, 0.16, None],
'sqqq': ['SQQQ', 15, 45, 1.5, -0.1, 5, 120, 60, 0.16, None],
}
# 1/4
self.fast, self.slow, self.atr = {}, {}, {}
for key, symbol in self.symbols.items():
code = symbol[0]
slow, fast = symbol[6], symbol[7]
if key in ['psq', 'rwm', 'tza', 'sqqq', 'slv']:
# 2/4
self.AddEquity(code, Resolution.Daily)
else:
raise RuntimeError(code + ' do not set market data ')
self.fast[code] = self.SMA(code, fast, Resolution.Daily)
self.slow[code] = self.SMA(code, slow, Resolution.Daily)
self.atr[code] = self.ATR(code, 15, MovingAverageType.Simple, Resolution.Daily)
self.PlotIndicator('atr' + code, self.atr[code])
self.PlotIndicator('fast' + code, self.fast[code])
self.PlotIndicator('slow' + code, self.slow[code])
self.SetWarmup(timedelta(300))
self.Log('for each iterate ' + str(self.Time))
if 'psq' in self.symbols:
self.Schedule.On(self.DateRules.EveryDay(self.symbols['psq'][0]), self.TimeRules.AfterMarketOpen(self.symbols['psq'][0], 10), self.run_psq)
if 'slv' in self.symbols:
self.Schedule.On(self.DateRules.EveryDay(self.symbols['slv'][0]), self.TimeRules.AfterMarketOpen(self.symbols['slv'][0], 10), self.run_slv)
if 'rwm' in self.symbols:
self.Schedule.On(self.DateRules.EveryDay(self.symbols['rwm'][0]), self.TimeRules.AfterMarketOpen(self.symbols['rwm'][0], 10), self.run_rwm)
if 'tza' in self.symbols:
self.Schedule.On(self.DateRules.EveryDay(self.symbols['tza'][0]), self.TimeRules.AfterMarketOpen(self.symbols['tza'][0], 45), self.run_tza)
if 'sqqq' in self.symbols:
self.Schedule.On(self.DateRules.EveryDay(self.symbols['sqqq'][0]), self.TimeRules.AfterMarketOpen(self.symbols['sqqq'][0], 45), self.run_sqqq)
# 3/4
self.Log(' Initialize schedule end ' + str(self.Time))
def run_psq(self):
self.Log('run_psq ' + str(self.Time))
self.run(self.symbols['psq'])
def run_slv(self):
self.Log('run_slv ' + str(self.Time))
self.run(self.symbols['slv'])
def run_rwm(self):
self.Log('run_rwm ' + str(self.Time))
self.run(self.symbols['rwm'])
def run_tza(self):
self.Log('run_tza ' + str(self.Time))
self.run(self.symbols['tza'])
def run_sqqq(self):
self.Log('run_sqqq ' + str(self.Time))
self.run(self.symbols['sqqq'])
def run_govt(self):
self.Log('run_govt ' + str(self.Time))
self.run(self.symbols['govt'])
# 4/4
# future trading ondata
def OnData(self, data):
for code in self.symbols:
a = 1 # just do nothing
# self.Log("data contains key " + self.symbols[code][0] + ' '
# + str(data.ContainsKey(self.symbols[code][0])) + ' ' + str(self.Time))
# stock trading logic
def run(self, symbol):
self.Log('run ' + str(symbol)+ ' ' + str(self.Time))
code = symbol[0]
pos_per_time = symbol[1]
max_pos = symbol[2]
atr_number = symbol[3]
pl_stop = symbol[4]
breakout = symbol[5]
take_profit_rate = symbol[8]
opens = self.History(self.Symbol(code), breakout, Resolution.Daily)['open']
uptrend, downtrend = False, False
if len(opens) >= 4:
uptrend = opens[-1] > opens[-2] and opens[-2] > opens[-3] and opens[-3] > opens[-4]
downtrend = opens[-1] < opens[-2] and opens[-2] < opens[-3] and opens[-3] < opens[-4]
if not self.slow[code].IsReady or not self.fast[code].IsReady or not self.atr[code].IsReady:
s = 'indicators is not ready ' + ' ' + str(self.Time)
self.Log(s)
return
p = self.Securities[code].Price
ma_slow = round(self.slow[code].Current.Value, 5)
ma_fast = round(self.fast[code].Current.Value, 5)
atr = round(self.atr[code].Current.Value, 5)
highest = max(opens)
lowest = min(opens)
pos = self.Portfolio[code].Quantity
avg_open = self.Portfolio[code].AveragePrice
pl = 0
if avg_open > 0:
if pos > 0:
pl = (p - avg_open) / avg_open
if pos < 0:
pl = (avg_open - p) / avg_open
s = (code
+ ' price ' + self.f(p)
+ ' position ' + self.f(pos)
+ ' avg_open ' + self.f(avg_open)
+ ' atr ' + self.f(atr)
+ ' ma_slow ' + self.f(ma_slow)
+ ' ma_fast ' + self.f(ma_fast)
+ ' highest ' + self.f(highest)
+ ' lowest ' + self.f(lowest)
+ ' pl ' + self.f(pl)
+ ' trailing_stop ' + self.f(symbol[9])
+ ' uptrend ' + str(uptrend)
+ ' downtrend ' + str(downtrend)
+ ' ' + str(self.Time))
self.Log(s)
is_long, is_short = pos > 0, pos < 0
if not is_long and not is_short:
symbol[9] = None
if symbol[9] is None and is_long:
symbol[9] = avg_open * (1 + pl_stop)
symbol[9] = max(symbol[9], avg_open - atr * atr_number)
if symbol[9] is None and is_short:
symbol[9] = avg_open * (1 - pl_stop)
symbol[9] = min(symbol[9], avg_open + atr * atr_number)
if is_long and pl > take_profit_rate and downtrend:
self.Liquidate(code)
self.Log(code + ' liquidate long by take profit when retreat')
is_long = False
pl = -1
symbol[9] = None
if is_short and pl > take_profit_rate and uptrend:
self.Liquidate(code)
self.Log(code + ' liquidate short by take profit when retreat')
is_short = False
pl = -1
symbol[9] = None
if is_long and pl > take_profit_rate and (highest - p) > 2 * atr:
self.Liquidate(code)
self.Log(code + ' liquidate long by take profit when retreat atr')
is_long = False
pl = -1
symbol[9] = None
if is_short and pl > take_profit_rate and (p - lowest) > 2 * atr:
self.Liquidate(code)
self.Log(code + ' liquidate short by take profit when retreat atr')
is_short = False
pl = -1
symbol[9] = None
if is_long:
stop_loss_p = avg_open - atr * atr_number
symbol[9]= max(symbol[9], stop_loss_p)
if p - avg_open > atr * atr_number:
symbol[9] = max(symbol[9], avg_open)
if p - avg_open > atr * atr_number * 2:
symbol[9] = max(symbol[9], avg_open + atr * atr_number)
if p - avg_open > atr * atr_number * 4:
symbol[9] = max(symbol[9], avg_open + atr * atr_number * 2)
if p - avg_open > atr * 2:
symbol[9] = max(symbol[9], p - atr * 2)
if p <= symbol[9]:
self.Liquidate(code)
self.Log(code + ' liquidate long by stop loss price ' + self.f(symbol[9]))
is_long = False
pl = -1
symbol[9] = None
if pl < pl_stop:
self.Liquidate(code)
self.Log(code + ' liquidate long by pl stop')
is_long = False
pl = -1
symbol[9] = None
if is_short:
stop_loss_p = avg_open + atr * atr_number
symbol[9] = min(symbol[9], stop_loss_p)
if avg_open - p > atr * atr_number:
symbol[9] = min(symbol[9], avg_open)
if avg_open - p > atr * atr_number * 2:
symbol[9] = min(symbol[9], avg_open - atr*atr_number)
if avg_open - p > atr * atr_number * 4:
symbol[9] = min(symbol[9], avg_open - atr*atr_number*2)
if avg_open - p > atr * 2:
symbol[9] = min(symbol[9], p + atr * 2)
if p >= symbol[9]:
self.Liquidate(code)
self.Log(code + ' liquidate short by stop loss price ' + self.f(symbol[9]))
is_short = False
pl = -1
symbol[9] = None
if pl < pl_stop:
self.Liquidate(code)
self.Log(code + ' liquidate short by pl stop')
is_short = False
pl = -1
symbol[9] = None
if is_long and (p < ma_fast or p < ma_slow):
self.Liquidate(code)
self.Log(code + ' liquidate long by ma fast or slow')
is_long = False
pl = -1
symbol[9] = None
if is_short and (p > ma_fast or p > ma_slow):
self.Liquidate(code)
self.Log(code + ' liquidate short by ma fast or slow')
is_short = False
pl = -1
symbol[9] = None
if (p >= ma_slow and p >= ma_fast and p >= highest
and abs(pos) < max_pos and pl >= 0):
self.MarketOrder(code, pos_per_time)
s = code + ' open long'
self.Log(s)
if (p <= ma_slow and p <= ma_fast and p <= lowest
and abs(pos) < max_pos and pl >= 0):
self.MarketOrder(code, pos_per_time * -1)
s = code + ' open short'
self.Log(s)
def OnEndOfDay(self, data):
pass
def OnOrderEvent(self, orderEvent):
order = self.Transactions.GetOrderById(orderEvent.OrderId)
if orderEvent.Status == OrderStatus.Filled:
self.Log("{0}: {1}: {2}".format(self.Time, order.Type, orderEvent))
def f(self, f):
if f is None:
return 'None'
if type(f) != float:
f = float(f)
s = str('{:.6f}'.format(f))
if s.endswith('.000000'):
s = s[:-7]
return s