| Overall Statistics |
|
Total Trades 37 Average Win 9.14% Average Loss -0.19% Compounding Annual Return 24.007% Drawdown 18.000% Expectancy 29.520 Net Profit 197.857% Sharpe Ratio 1.688 Probabilistic Sharpe Ratio 86.366% Loss Rate 39% Win Rate 61% Profit-Loss Ratio 49.14 Alpha 0.191 Beta 0.322 Annual Standard Deviation 0.151 Annual Variance 0.023 Information Ratio 0.299 Tracking Error 0.188 Treynor Ratio 0.793 Total Fees $1111.45 Estimated Strategy Capacity $120000000.00 Lowest Capacity Asset TLT SGNKIKYGE9NP |
import numpy as np
import pandas as pd
class NaturalResources(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2016, 7, 1)
self.SetCash(1000000)
self.SetBrokerageModel(BrokerageName.AlphaStreams)
rebalance_period = timedelta(days=7)
self.SetPortfolioConstruction(InsightWeightingPortfolioConstructionModel(rebalance_period))
self.Settings.RebalancePortfolioOnInsightChanges = False
self.SetExecution(ImmediateExecutionModel())
res = Resolution.Hour
self.UniverseSettings.Resolution = res
market = ['SPY']
bonds = ['TLT']
signals = ['IGE']
self.market = [self.AddEquity(ticker, res).Symbol for ticker in market]
self.bonds = [self.AddEquity(ticker, res).Symbol for ticker in bonds]
self.signals = [self.AddEquity(ticker, res).Symbol for ticker in signals]
self.AddAlpha(NaturalResourcesEvent(self.market,
self.bonds,
self.signals,
))
class NaturalResourcesEvent(AlphaModel):
"""
"""
def __init__(self,
market,
bonds,
signals):
self.Name = 'Natural Resources Event'
self.market = market
self.bonds = bonds
self.signals = signals
# Rolling mean of signal:
self.rolling_mean = 55
self.past_days = 365
# Out of market waiting days:
self.wait_days = 15
# Percentiles of extreme:
self.extreme_p = 5
self.be_in = True
self.hold_days = timedelta(days=1)
self.gain = 0.02
self.dcount = False
def Update(self, algorithm, data):
if algorithm.Time.hour != 10 or algorithm.Time.minute != 0:
return []
insights = []
# Sample to detect extreme observations:
hist = algorithm.History(self.signals, self.past_days,
Resolution.Daily)['close']
hist = hist.unstack(level=0).dropna()
# Rolling mean smoothing out of values:
hist_shift = hist.rolling(window=self.rolling_mean).mean().dropna()
# As returns:
returns_sample = (hist / hist_shift - True)
# Extreme observations at given percentile
pctl_b = np.nanpercentile(returns_sample,
self.extreme_p,
axis=int(False))
extreme_b = returns_sample.iloc[-True] < pctl_b
alarms_on = extreme_b[self.signals].any()
# Determine whether 'in' or 'out' of the market
if alarms_on:
self.be_in = False
if self.dcount >= self.wait_days:
self.be_in = True
if self.be_in:
for symbol in self.market:
weight = int(True)
insights.append(Insight(symbol, self.hold_days,
InsightType.Price,
InsightDirection.Up,
self.gain, int(True),
self.Name, weight))
self.dcount = False
return insights
else:
algorithm.Log('Market Event incoming. Entering safe positions.')
for symbol in self.bonds:
insights.append(Insight(symbol, self.hold_days,
InsightType.Price,
InsightDirection.Up,
self.gain, int(True),
self.Name, int(True)))
self.dcount += True
return insights