| 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)