Overall Statistics |
Total Orders 149 Average Win 0.52% Average Loss -1.02% Compounding Annual Return -20.673% Drawdown 15.700% Expectancy -0.081 Start Equity 37700 End Equity 35225.42 Net Profit -6.564% Sharpe Ratio -0.742 Sortino Ratio -0.785 Probabilistic Sharpe Ratio 15.887% Loss Rate 39% Win Rate 61% Profit-Loss Ratio 0.51 Alpha -0.267 Beta 0.9 Annual Standard Deviation 0.241 Annual Variance 0.058 Information Ratio -1.558 Tracking Error 0.178 Treynor Ratio -0.199 Total Fees $165.94 Estimated Strategy Capacity $37000000.00 Lowest Capacity Asset WAG R735QTJ8XC9X Portfolio Turnover 27.59% |
# region imports from AlgorithmImports import * from alpha_1637 import Strategy001AlphaModel from porfolio_1737 import Stragety001PortfolioConstructionModel # endregion class MeanReversionAlgorithm(QCAlgorithm): def initialize(self): # self.settings.daily_precise_end_time = False self.set_start_date(2024, 5, 30) self.set_end_date(2024, 12, 30) self.set_cash(37700) # Set Strategy Cash self.set_warm_up(timedelta(days=3), Resolution.DAILY) self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN) self.add_universe_selection(ETFConstituentsUniverseSelectionModel("QQQ")) self.universe_settings.resolution = Resolution.DAILY self.set_benchmark("QQQ") self.add_alpha(Strategy001AlphaModel()) self.set_portfolio_construction(Stragety001PortfolioConstructionModel()) self.set_execution(ImmediateExecutionModel())
#region imports from AlgorithmImports import * import time import random #endregion class Strategy001AlphaModel(AlphaModel): basket_capacity = 8 trade_bar_count = 0 trade_bar_none_count = 0 def __init__(self): self.entry_rolling_window_dict = {} self.exit_rolling_window_dict = {} def update(self, algorithm, data): self.entry_insights_update(algorithm, data) self.exit_insights_update(algorithm, data) if data.time.weekday() == 4: # close time on Friday algorithm.debug(f"{self.trade_bar_none_count}/{self.trade_bar_count}={self.trade_bar_none_count / self.trade_bar_count} trade_bar is None {data.time.year}-{data.time.month}-{data.time.day} {data.time.hour}:{data.time.minute}:{data.time.second}") algorithm.debug(f"len(data)={len(data)}") if len(data) < 10: for symbol, trade_bar in data.items(): algorithm.debug(f"{symbol.value}") exit_insights_count = self.exit_insights_create(algorithm, data) entry_insights_list = [] if data.time.weekday() == 0: # close time on Monday entry_insights_list = self.entry_insights_create(algorithm, data) securities_count = 0 for security_holding in algorithm.portfolio.values(): if security_holding.invested: securities_count += 1 index = min(self.basket_capacity - (securities_count - exit_insights_count), self.basket_capacity) entry_insights_list = entry_insights_list[:index] return entry_insights_list def entry_insights_create(self, algorithm, data): entry_insights_list = [] for symbol, trade_bar in data.items(): if (self.entry_rolling_window_dict[symbol].count == 3) \ and (not algorithm.portfolio[symbol].invested): if (self.entry_rolling_window_dict[symbol][0].close < self.entry_rolling_window_dict[symbol][1].close) \ and (self.entry_rolling_window_dict[symbol][1].close < self.entry_rolling_window_dict[symbol][2].close) \ and (self.entry_rolling_window_dict[symbol][0].close > 5.0): entry_insights_list.append( Insight( symbol=symbol, period=timedelta(days=365 * 10), type=InsightType.PRICE, direction=InsightDirection.UP, magnitude=self.entry_rolling_window_dict[symbol][0].volume, confidence=1.0)) sorted_active_insights = sorted(entry_insights_list, key=lambda x: x.magnitude, reverse=True) return sorted_active_insights def exit_insights_create(self, algorithm, data): exit_insights_count = 0 for symbol, trade_bar in data.items(): if (self.exit_rolling_window_dict[symbol].count == 2) and algorithm.portfolio[symbol].invested: if self.exit_rolling_window_dict[symbol][0].close > self.exit_rolling_window_dict[symbol][1].high: assert algorithm.insights.contains_key(symbol) assert len(algorithm.insights[symbol]) == 1 algorithm.insights[symbol][0].expire(algorithm.utc_time) exit_insights_count += 1 return exit_insights_count def exit_insights_update(self, algorithm, data): for symbol, trade_bar in data.items(): if trade_bar is None: # algorithm.error(f"{symbol.value}:trade_bar is None, reset exit_rolling_window") self.trade_bar_none_count += 1 self.exit_rolling_window_dict[symbol].reset() else: self.exit_rolling_window_dict[symbol].add(trade_bar) self.trade_bar_count += 1 def entry_insights_update(self, algorithm, data): if data.time.weekday() in [3, 4, 0]: # close time on Thursday, Friday and Monday for symbol, trade_bar in data.items(): if trade_bar is None: # algorithm.error(f"{symbol.value}:trade_bar is None, reset entry_rolling_window") self.trade_bar_none_count += 1 self.entry_rolling_window_dict[symbol].reset() else: self.entry_rolling_window_dict[symbol].add(trade_bar) self.trade_bar_count += 1 def on_securities_changed(self, algorithm, changes): for security in changes.added_securities: self.entry_rolling_window_dict.setdefault(security.symbol, RollingWindow[TradeBar](3)) self.exit_rolling_window_dict.setdefault(security.symbol, RollingWindow[TradeBar](2))
#region imports from AlgorithmImports import * import time from alpha_1637 import Strategy001AlphaModel #endregion # Portfolio construction scaffolding class; basic method args. class Stragety001PortfolioConstructionModel(EqualWeightingPortfolioConstructionModel): total_position = 1.6 # Determines the target percent for each insight def determine_target_percent(self, activeInsights: List[Insight]) -> Dict[Insight, float]: targets = {} for insight in activeInsights: if not self.algorithm.portfolio[insight.symbol].invested: # new targets if insight.direction is InsightDirection.UP: targets[insight] = self.total_position / Strategy001AlphaModel.basket_capacity return targets