Overall Statistics |
Total Orders 25 Average Win 4.88% Average Loss -1.25% Compounding Annual Return 7.717% Drawdown 11.600% Expectancy 0.632 Start Equity 100000 End Equity 107017.24 Net Profit 7.017% Sharpe Ratio 0.236 Sortino Ratio 0.264 Probabilistic Sharpe Ratio 24.392% Loss Rate 67% Win Rate 33% Profit-Loss Ratio 3.90 Alpha -0.075 Beta 0.628 Annual Standard Deviation 0.163 Annual Variance 0.026 Information Ratio -0.932 Tracking Error 0.153 Treynor Ratio 0.061 Total Fees $144.71 Estimated Strategy Capacity $630000.00 Lowest Capacity Asset BW W1U0W5MNRKO5 Portfolio Turnover 0.73% |
from typing import List, Iterable from AlgorithmImports import * from QuantConnect import * from QuantConnect.Algorithm import QCAlgorithm from QuantConnect.Data.UniverseSelection import * class QuarterlyRebalancingAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2019, 1, 1) self.set_end_date(2019, 12, 1) self.set_cash(100000) self.add_universe(self.coarse_selection_function, self.fine_selection_function) self.schedule.on(self.date_rules.month_start(1), self.time_rules.at(9, 31), self.liquidate_positions) self.schedule.on(self.date_rules.month_start(1), self.time_rules.at(9, 35), self.rebalance) self.set_security_initializer(lambda security: security.set_fee_model(ConstantFeeModel(1))) # Set transaction fees and slippage self.set_security_initializer(lambda security: security.set_slippage_model(ConstantSlippageModel(0.001))) self.quarterly_rebalance = False self.selected_symbols: List[symbol] = [] self.liquidate_positions_counter = 0 self.rebalance_counter = 0 def liquidate_positions(self): if self.liquidate_positions_counter == 0 or self.liquidate_positions_counter == 3: for symbol in list(self.portfolio.keys()): self.liquidate(symbol) self.liquidate_positions_counter += 1 if self.liquidate_positions_counter >= 3: self.liquidate_positions_counter = 1 else: self.liquidate_positions_counter += 1 def rebalance(self): if self.rebalance_counter == 0 or self.rebalance_counter == 3: weight = 1 / 10 for symbol in self.selected_symbols: self.log(",".join([str(symbol.value) for symbol in self.selected_symbols])) self.set_holdings(symbol, weight) self.rebalance_counter += 1 if self.rebalance_counter >= 3: self.rebalance_counter = 1 else: self.rebalance_counter += 1 def coarse_selection_function(self, coarse): filtered = [x for x in coarse if x.price > 0.5]# and x.dollar_volume > 10000000] #filtered = [x for x in filtered if x.primary_exchange in ["NASDAQ", "NYSE"]] filtered = [x for x in filtered if not x.symbol.value.endswith(".OB")] return [x.symbol for x in filtered] def fine_selection_function(self, fine: List[FineFundamental]) -> List[Symbol]: selected_securities = [] sortedsec= [] selected = [c for c in fine if c.has_fundamental_data and not np.isnan(c.valuation_ratios.pe_ratio)] for f in selected: if f is not None: if f.market_cap >= 50000000 and f.valuation_ratios.pe_ratio is not None and f.valuation_ratios.pe_ratio > 0: selected_securities.append(f) sorted_securities = sorted(selected_securities, key=lambda x: x.valuation_ratios.pe_ratio, reverse=False) sortedsec = [c.symbol for c in sorted_securities] return sortedsec[:10] def on_securities_changed(self, changes: Iterable[SecurityChanges]) -> List[Symbol]: self.selected_symbols = [] for security in changes.added_securities: self.selected_symbols.append(security.Symbol)