| Overall Statistics |
|
Total Orders 24 Average Win 6.24% Average Loss -3.72% Compounding Annual Return 15.983% Drawdown 12.600% Expectancy 0.461 Start Equity 100000 End Equity 134412.37 Net Profit 34.412% Sharpe Ratio 0.642 Sortino Ratio 0.662 Probabilistic Sharpe Ratio 41.094% Loss Rate 45% Win Rate 55% Profit-Loss Ratio 1.68 Alpha 0.08 Beta 0.38 Annual Standard Deviation 0.127 Annual Variance 0.016 Information Ratio 0.473 Tracking Error 0.165 Treynor Ratio 0.214 Total Fees $33.46 Estimated Strategy Capacity $980000000.00 Lowest Capacity Asset QQQ RIWIV7K5Z9LX Portfolio Turnover 2.83% |
# region imports
from AlgorithmImports import *
# endregion
class VirtualAsparagusSheep(QCAlgorithm):
def initialize(self):
self.set_start_date(2022, 1, 1)
self.set_end_date(2024, 1, 1)
self.set_cash(100000)
self.qqq = self.add_equity("QQQ", Resolution.DAILY).symbol
# qqq.set_data_normalization_mode(DataNormalizationMode.RAW)
self.entryTicket = None
self.stopMarketTicket = None
self.entryTime = datetime.min
self.stopMarketOrderFillTime = datetime.min
self.highestPrice = 0
self.set_benchmark("QQQ")
# self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.CASH)
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 already invested or sent the order
if not self.portfolio.invested and not self.transactions.get_open_orders(self.qqq):
quantity = self.calculate_order_quantity(self.qqq, 0.9)
# LIMIT ORDER SENT HERE
self.entryTicket = self.limit_order(self.qqq, quantity, price, "Entry order")
self.entryTime = self.time
# move limit price if limit order not filled after 1 day
if (self.time - self.entryTime).days > 1 and self.entryTicket.status != OrderStatus.FILLED:
self.entryTime = self.time
updateFields = UpdateOrderFields()
updateFields.limit_price = price
self.entryTicket.update(updateFields)
# move up trailing stop price if invested and stop loss ticket exists
if self.stopMarketTicket is not None and self.portfolio.invested:
if price > self.highestPrice:
self.highestPrice = price
updateFields = UpdateOrderFields()
updateFields.stop_price = price * 0.95
self.stopMarketTicket.update(updateFields)
def on_order_event(self, orderEvent):
# waiting
if orderEvent.status != OrderStatus.FILLED:
return
# send trailing stop loss order if entry limit order is filled
if self.entryTicket is not None and self.entryTicket.order_id == orderEvent.order_id:
# STOP LOSS ORDER SENT HERE
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 == orderEvent.order_id:
self.stopMarketOrderFillTime = self.time
self.highestPrice = 0