| Overall Statistics |
|
Total Orders 1791 Average Win 0.66% Average Loss -0.78% Compounding Annual Return -5.743% Drawdown 36.900% Expectancy -0.030 Start Equity 100000 End Equity 74392.34 Net Profit -25.608% Sharpe Ratio -0.373 Sortino Ratio -0.46 Probabilistic Sharpe Ratio 0.090% Loss Rate 47% Win Rate 53% Profit-Loss Ratio 0.84 Alpha -0.062 Beta -0.007 Annual Standard Deviation 0.167 Annual Variance 0.028 Information Ratio -0.633 Tracking Error 0.22 Treynor Ratio 8.642 Total Fees $1945.08 Estimated Strategy Capacity $5100000.00 Lowest Capacity Asset ICE TDPZZM7IWEP1 Portfolio Turnover 5.78% Drawdown Recovery 462 |
#region imports
from AlgorithmImports import *
#endregion
#This is a Template of dynamic stock selection.
#You can try your own fundamental factor and ranking method by editing the _select method
class BasicTemplateAlgorithm(QCAlgorithm):
_long = []
_short = []
def initialize(self):
self.set_start_date(self.end_date - timedelta(5*365))
self.set_cash(100000)
self.settings.seed_initial_prices = True
date_rules = self.date_rules.month_start("SPY")
self.universe_settings.schedule.on(date_rules)
self.add_universe(self._select)
# Schedule the rebalance function to execute at the begining of each month
self.schedule.on(date_rules, self.time_rules.after_market_open("SPY", 5), self._rebalance)
def _select(self, fundamental):
top_volume = 250
top_rank = 10
# Drop stocks which don't have the information we need or have too low prices
# You can try replacing those factor with your own factors here
fundamental = sorted(
[x for x in fundamental if x.price > 5
and not any([np.isnan(x.valuation_ratios.price_change_1m),
np.isnan(x.valuation_ratios.book_value_per_share),
np.isnan(x.operation_ratios.operation_margin.value)]) ],
key=lambda x: x.dollar_volume, reverse=True)
self.plot('Universe', '-', len(fundamental))
fundamental = fundamental[:top_volume]
# Rank stocks by three factor.
sorted_by_factor1 = sorted(fundamental, key=lambda x: x.valuation_ratios.price_change_1m, reverse=True)
sorted_by_factor2 = sorted(fundamental, key=lambda x: x.valuation_ratios.book_value_per_share, reverse=True)
sorted_by_factor3 = sorted(fundamental, key=lambda x: x.operation_ratios.operation_margin.value, reverse=True)
# Assign a score to each stock, you can also change the rule of scoring here.
stock_dict = {}
for rank1, ele in enumerate(sorted_by_factor1):
rank2 = sorted_by_factor2.index(ele)
rank3 = sorted_by_factor3.index(ele)
stock_dict[ele] = .2*rank1 + .4*rank2 + .4*rank3
# Store the top stocks into the long_list and the bottom ones into the short_list
sorted_stock = sorted(stock_dict.items(), key=lambda d:d[1],reverse=False)
self._long = [x.symbol for x,_ in sorted_stock[:top_rank]]
self._short = [x.symbol for x,_ in sorted_stock[-top_rank:]]
return self._long + self._short
def _rebalance(self):
# Alternatively, you can liquidate all the stocks at the end of each month.
# Which method to choose depends on your investment philosiphy
# if you prefer to realized the gain/loss each month, you can choose this method.
# self.liquidate()
# In this example, we will have a long bias
targets = [PortfolioTarget(s, 1.0/len(self._long)) for s in self._long]
targets += [PortfolioTarget(s, -0.5/len(self._short)) for s in self._short]
self.set_holdings(targets, liquidate_existing_holdings=True)