| Overall Statistics |
|
Total Orders 570 Average Win 0.41% Average Loss -0.29% Compounding Annual Return 2.826% Drawdown 12.200% Expectancy 0.097 Start Equity 100000 End Equity 114958.48 Net Profit 14.958% Sharpe Ratio -0.257 Sortino Ratio -0.307 Probabilistic Sharpe Ratio 3.612% Loss Rate 54% Win Rate 46% Profit-Loss Ratio 1.39 Alpha -0.001 Beta -0.224 Annual Standard Deviation 0.065 Annual Variance 0.004 Information Ratio -0.474 Tracking Error 0.182 Treynor Ratio 0.074 Total Fees $817.57 Estimated Strategy Capacity $70000.00 Lowest Capacity Asset ETM RHT4ZGXEX36T Portfolio Turnover 0.86% Drawdown Recovery 364 |
#region imports
from AlgorithmImports import *
from collections import deque
import calendar
#endregion
class BetaAlphaModel(AlphaModel):
def __init__(self, algorithm, benchmark, date_rule):
self._benchmark = benchmark
self._securities = []
self._insights = []
# Add a Scheduled Event to emit monthly insights.
algorithm.schedule.on(date_rule, algorithm.time_rules.at(8, 0), self._create_insights)
def on_securities_changed(self, algorithm, changes):
# As assets enter the universe, create their beta indicators.
for security in changes.added_securities:
if security != self._benchmark:
security.beta = algorithm.b(security, self._benchmark, 252)
self._securities.append(security)
# As assets leave the universe, stop updating their beta indicators.
for security in changes.removed_securities:
algorithm.deregister_indicator(security.beta)
self._securities.remove(security)
def _create_insights(self):
# Sort the securities by their beta factor.
sorted_by_beta = sorted(
[security for security in self._securities if security.beta.is_ready],
key=lambda security: security.beta
)
# Create insights that will form a long-short portfolio.
positions_per_side = int(0.25*len(sorted_by_beta))
weight = 0.5 / positions_per_side
self._insights = [
Insight.price(security, Expiry.END_OF_MONTH, InsightDirection.UP, weight=weight)
for security in sorted_by_beta[:positions_per_side]
] + [
Insight.price(security, Expiry.END_OF_MONTH, InsightDirection.DOWN, weight=weight)
for security in sorted_by_beta[-positions_per_side:]
]
def update(self, algorithm, data):
# Return our monthly insights for the portfolio construction model.
insights = self._insights.copy()
self._insights = []
return insights
#region imports
from AlgorithmImports import *
from alpha import BetaAlphaModel
#endregion
class BetaAlgorithm(QCAlgorithmFramework):
def initialize(self):
self.set_start_date(self.end_date - timedelta(5*365))
self.set_cash(100_000)
# Add a universe of country index ETFs.
self.universe_settings.resolution = Resolution.DAILY
tickers = [
"EWJ", # iShares MSCI Japan Index ETF
"EZU", # iShares MSCI Eurozone ETF
"EFNL", # iShares MSCI Finland Capped Investable Market Index ETF
"EWW", # iShares MSCI Mexico Inv. Mt. Idx
"ERUS", # iShares MSCI Russia ETF
"IVV", # iShares S&P 500 Index
"ICOL", # Consumer Discretionary Select Sector SPDR Fund
"AAXJ", # iShares MSCI All Country Asia ex Japan Index ETF
"AUD", # Australia Bond Index Fund
"EWQ", # iShares MSCI France Index ETF
"BUND", # Pimco Germany Bond Index Fund
"EWH", # iShares MSCI Hong Kong Index ETF
"EPI", # WisdomTree India Earnings ETF
"EIDO" # iShares MSCI Indonesia Investable Market Index ETF
"EWI", # iShares MSCI Italy Index ETF
"GAF", # SPDR S&P Emerging Middle East & Africa ETF
"ENZL", # iShares MSCI New Zealand Investable Market Index Fund
"NORW" # Global X FTSE Norway 30 ETF
"EWY", # iShares MSCI South Korea Index ETF
"EWP", # iShares MSCI Spain Index ETF
"EWD", # iShares MSCI Sweden Index ETF
"EWL", # iShares MSCI Switzerland Index ETF
"GXC", # SPDR S&P China ETF
"EWC", # iShares MSCI Canada Index ETF
"EWZ", # iShares MSCI Brazil Index ETF
"ARGT", # Global X FTSE Argentina 20 ETF
"AND", # Global X FTSE Andean 40 ETF
"AIA", # iShares S&P Asia 50 Index ETF
"EWO", # iShares MSCI Austria Investable Mkt Index ETF
"EWK", # iShares MSCI Belgium Investable Market Index ETF
"BRAQ", # Global X Brazil Consumer ETF
"ECH", # iShares MSCI Chile Investable Market Index ETF
"CHIB", # Global X China Technology ETF
"EGPT", # Market Vectors Egypt Index ETF
"ADRU" # BLDRS Europe 100 ADR Index ETF
]
symbols = [Symbol.create(ticker, SecurityType.EQUITY, Market.USA) for ticker in tickers]
self.set_universe_selection(ManualUniverseSelectionModel(symbols))
# Add an Alpha model that emits insights based on beta.
self.settings.automatic_indicator_warm_up = True
benchmark = self.add_equity("SPY", Resolution.DAILY)
date_rule = self.date_rules.month_start(benchmark)
self.set_alpha(BetaAlphaModel(self, benchmark, date_rule))
# Add a portfolio construction model.
self.settings.rebalance_portfolio_on_insight_changes = False
self.settings.rebalance_portfolio_on_security_changes = False
self.set_portfolio_construction(InsightWeightingPortfolioConstructionModel(date_rule))
# Add the risk and execution models.
self.set_risk_management(NullRiskManagementModel())
self.set_execution(ImmediateExecutionModel())
# Add a warm-up period so the algorithm trades right away.
self.set_warm_up(timedelta(45))