| Overall Statistics |
|
Total Orders 32 Average Win 4.62% Average Loss -3.74% Compounding Annual Return 8.188% Drawdown 16.200% Expectancy 0.341 Start Equity 100000 End Equity 126648.61 Net Profit 26.649% Sharpe Ratio 0.438 Sortino Ratio 0.347 Probabilistic Sharpe Ratio 22.070% Loss Rate 40% Win Rate 60% Profit-Loss Ratio 1.23 Alpha 0.023 Beta 0.195 Annual Standard Deviation 0.094 Annual Variance 0.009 Information Ratio -0.309 Tracking Error 0.175 Treynor Ratio 0.211 Total Fees $72.89 Estimated Strategy Capacity $73000000.00 Lowest Capacity Asset QQQ RIWIV7K5Z9LX Portfolio Turnover 2.54% Drawdown Recovery 707 |
# region imports
from AlgorithmImports import *
# endregion
class SleepyApricotDog(QCAlgorithm):
def initialize(self):
self.set_start_date(2018, 1, 1)
self.set_end_date(2021, 1, 1)
self.set_cash(100000)
self.qqq = self.add_equity("QQQ", Resolution.HOUR).symbol
self.entryTicket = None
self.stopMarketTicket = None
self.entryTime = self.time
self.stopMarketOrderFillTime = self.time
self.highestPrice = 0
def on_data(self, data: Slice):
# wait 30 days after last exit
if (self.time - self.stopMarketOrderFillTime).days < 30:
return
price = self.securities[self.qqq].price
# send entry limit order
if not self.portfolio.invested and not self.transactions.get_open_orders(self.qqq):
quantity = self.calculate_order_quantity(self.qqq, 0.9)
self.entryTicket = self.limit_order(self.qqq, quantity, price, tag="Entry Order")
self.entryTime = self.time
# move limit price if not filled after 1 day
if (self.time - self.entryTime).days > 1 and self.entryTicket.status != OrderStatus.FILLED:
self.entryTime = self.time
updateFileds = UpdateOrderFields()
updateFileds.limit_price = price
self.entryTicket.update(updateFileds)
# move up trailing stop price
if self.stop_market_order is not None and self.portfolio.invested:
if price > self.highestPrice:
self.highestPrice = price
updateFileds = UpdateOrderFields()
updateFileds.stop_price = price * 0.95
self.stopMarketTicket.update(updateFileds)
self.debug(updateFileds.stop_price)
def on_order_event(self, order_event):
if order_event.status != OrderStatus.FILLED:
return
# send stop loss order if entry limit order is filled
if self.entryTicket is not None and self.entryTicket.order_id == order_event.order_id:
self.stopMarketTicket = self.stop_market_order(self.qqq, -self.entryTicket.quantity, 0.95*self.entryTicket.average_fill_price)
# save fill time of stop loss order
if self.stopMarketTicket is not None and self.stopMarketTicket.order_id == order_event.order_id:
self.stopMarketOrderFillTime = self.time
self.highestPrice = 0