| Overall Statistics |
|
Total Trades 7880 Average Win 0.47% Average Loss -0.20% Compounding Annual Return 7.332% Drawdown 58.800% Expectancy 0.278 Net Profit 328.552% Sharpe Ratio 0.369 Probabilistic Sharpe Ratio 0.019% Loss Rate 62% Win Rate 38% Profit-Loss Ratio 2.40 Alpha 0.075 Beta -0.016 Annual Standard Deviation 0.201 Annual Variance 0.04 Information Ratio 0.062 Tracking Error 0.264 Treynor Ratio -4.711 Total Fees $0.00 |
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// Represents the traditional simple moving average indicator (SMA)
/// </summary>
public class SkewIndicator : BarIndicator
{
public RollingWindow<decimal> bars;
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => bars.IsReady;
int Period;
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
bars.Reset();
base.Reset();
}
/// <summary>
/// Initializes a new instance of the SimpleMovingAverage class with the specified name and period
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The period of the SMA</param>
public SkewIndicator(string name, int period)
: base(name)
{
bars = new RollingWindow<decimal>(period);
Period = period;
}
/// <summary>
/// Initializes a new instance of the SimpleMovingAverage class with the default name and period
/// </summary>
/// <param name="period">The period of the SMA</param>
public SkewIndicator(int period)
: this("Skew" + period, period)
{
}
/// <summary>
/// Computes the next value for this indicator from the given state.
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input value to this indicator on this time step</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
bars.Add(input.Close);
if (!bars.IsReady) return 0;
return Skewness(ToIEnumerable());
}
public decimal Skewness(IEnumerable<double> list)
{
try
{
var d = MathNet.Numerics.Statistics.Statistics.Skewness(list);
if (d >= (double)Decimal.MaxValue) return Decimal.MaxValue;
if (d <= (double)Decimal.MinValue) return Decimal.MinValue;
return Convert.ToDecimal(d);
}
catch(OverflowException)
{
return 0;
}
}
private IEnumerable<double> ToIEnumerable()
{
var e = bars.GetEnumerator();
while (e.MoveNext())
{
yield return (double)e.Current;
}
}
}
}using System;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Securities;
using QuantConnect.Algorithm.CSharp;
namespace QuantConnect.Algorithm.Framework.Alphas
{
/// <summary>
/// Alpha model that uses an Skewness cross to create insights
/// </summary>
public class AlphaSkew : AlphaModel
{
private readonly int _periods;
private readonly Resolution _resolution;
private readonly int _predictionInterval;
private readonly Dictionary<Symbol, SymbolData> _symbolDataBySymbol;
private List<Insight> lastinsights = new List<Insight>();
private DateTime lastInsightDate;
/// <summary>
/// Initializes a new instance of the <see cref="EmaCrossAlphaModel"/> class
/// </summary>
/// <param name="fastPeriod">The fast EMA period</param>
/// <param name="slowPeriod">The slow EMA period</param>
/// <param name="resolution">The resolution of data sent into the EMA indicators</param>
public AlphaSkew(
Resolution resolution = Resolution.Minute,
int periods = 1440,
int predictionInterval = 1440
)
{
_resolution = resolution;
_periods = periods;
_predictionInterval = predictionInterval;
_symbolDataBySymbol = new Dictionary<Symbol, SymbolData>();
Name = $"{nameof(AlphaSkew)}({periods},{resolution})";
}
/// <summary>
/// Updates this alpha model with the latest data from the algorithm.
/// This is called each time the algorithm receives data for subscribed securities
/// </summary>
/// <param name="algorithm">The algorithm instance</param>
/// <param name="data">The new data available</param>
/// <returns>The new insights generated</returns>
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
var insights = new List<Insight>();
if(data==null) return insights;
if(lastInsightDate==null || algorithm.Time.Subtract(lastInsightDate).TotalDays > 2)
{
var insightPeriod = _resolution.ToTimeSpan().Multiply(_predictionInterval).Add(new TimeSpan(0,10,0));
lastInsightDate = algorithm.Time;
Dictionary<SymbolData, decimal> skews = new Dictionary<SymbolData, decimal>();
foreach (var symbolData in _symbolDataBySymbol.Values)
{
if(symbolData.Skew.IsReady && algorithm.Securities[symbolData.Symbol].Price>0)
skews[symbolData] = symbolData.Skew;
}
var ascskews = skews.Where(x=> x.Value>1m).OrderByDescending(pair => pair.Value).Take(2).ToDictionary(pair => pair.Key, pair => pair.Value).Keys;
var desskews = skews.Where(x=> x.Value<-1m).OrderBy(pair => pair.Value).Take(2).ToDictionary(pair => pair.Key, pair => pair.Value).Keys;
foreach (var symbolData in ascskews)
{
if (symbolData == null) continue;
var symbol = symbolData.Ticker;
if(algorithm.IsMarketOpen(symbol))
{
if(IsDateOK(algorithm.Time,symbolData.insightDate) )
{
insights.Add(Insight.Price(symbolData.Symbol, insightPeriod, InsightDirection.Up, Math.Abs(symbolData.ROCValue()), null));
symbolData.insightDate = algorithm.Time.Add(insightPeriod);
symbolData.TradePrice = algorithm.Securities[symbolData.Symbol].Price;
}
}
}
foreach (var symbolData in desskews)
{
if (symbolData == null) continue;
var symbol = symbolData.Ticker;
if(algorithm.IsMarketOpen(symbol))
{
if(IsDateOK(algorithm.Time,symbolData.insightDate) )
{
insights.Add(Insight.Price(symbolData.Symbol, insightPeriod, InsightDirection.Down, Math.Abs(symbolData.ROCValue()), null));
symbolData.insightDate = algorithm.Time.Add(insightPeriod);
symbolData.TradePrice = algorithm.Securities[symbolData.Symbol].Price;
}
}
}
var toFlat = _symbolDataBySymbol.Values.ToList().Except(ascskews).ToList().Except(desskews).ToList();
foreach (var symbolData in toFlat)
{
if(algorithm.IsMarketOpen(symbolData.Symbol))
{
if(IsDateOK(algorithm.Time,symbolData.insightDate) && algorithm.Securities[symbolData.Symbol].Price>0)
{
insights.Add(Insight.Price(symbolData.Symbol, insightPeriod, InsightDirection.Flat, Math.Abs(symbolData.ROCValue()), null));
symbolData.insightDate = algorithm.Time.Add(insightPeriod);
symbolData.TradePrice = 0;
symbolData.MaxPrice = 0;
}
}
}
lastinsights = insights;
return insights;
}
else
{
return RollOrCutOffAlpha(algorithm);
}
}
private IEnumerable<Insight> RollOrCutOffAlpha(QCAlgorithm algorithm)
{
var insights = new List<Insight>();
var insightPeriod = _resolution.ToTimeSpan().Multiply(_predictionInterval).Add(new TimeSpan(0,10,0));
//push insights again
foreach (var i in lastinsights)
{
var symbolData = _symbolDataBySymbol[i.Symbol];
if(i.Direction==InsightDirection.Down)
symbolData.MaxPrice = symbolData.MaxPrice==0?algorithm.Securities[i.Symbol].Price:Math.Min(symbolData.MaxPrice,algorithm.Securities[i.Symbol].Price);
else if(i.Direction==InsightDirection.Up)
symbolData.MaxPrice = Math.Max(symbolData.MaxPrice,algorithm.Securities[i.Symbol].Price);
if(_symbolDataBySymbol[i.Symbol].TradePrice>0 &&
((i.Direction==InsightDirection.Up && algorithm.Securities[i.Symbol].Price/_symbolDataBySymbol[i.Symbol].MaxPrice<0.9m)
|| (i.Direction==InsightDirection.Down && _symbolDataBySymbol[i.Symbol].MaxPrice/algorithm.Securities[i.Symbol].Price<0.9m)))
// if(algorithm.Securities[i.Symbol].Invested && algorithm.Securities[i.Symbol].Holdings.UnrealizedProfitPercent<-0.1m)
{
insights.Add(Insight.Price(i.Symbol, insightPeriod, InsightDirection.Flat, i.Magnitude, null));
_symbolDataBySymbol[i.Symbol].insightDate = algorithm.Time.Add(insightPeriod);
_symbolDataBySymbol[i.Symbol].TradePrice=0;
_symbolDataBySymbol[i.Symbol].MaxPrice=0;
}
else if(_symbolDataBySymbol[i.Symbol].TradePrice>0 &&
((i.Direction==InsightDirection.Up && algorithm.Securities[i.Symbol].Price/_symbolDataBySymbol[i.Symbol].TradePrice>0.98m)
|| (i.Direction==InsightDirection.Down && _symbolDataBySymbol[i.Symbol].TradePrice/algorithm.Securities[i.Symbol].Price>0.98m)))
{
if(IsDateOK(algorithm.Time,_symbolDataBySymbol[i.Symbol].insightDate) )
insights.Add(Insight.Price(i.Symbol, insightPeriod, i.Direction, i.Magnitude, null));
}
else if (i.Direction!=InsightDirection.Flat )//&& ((i.Direction==InsightDirection.Up && _symbolDataBySymbol[i.Symbol].Skew.Current.Value<1)||(i.Direction==InsightDirection.Down && _symbolDataBySymbol[i.Symbol].Skew.Current.Value>-1)))
{
insights.Add(Insight.Price(i.Symbol, insightPeriod, InsightDirection.Flat, i.Magnitude, null));
_symbolDataBySymbol[i.Symbol].insightDate = algorithm.Time.Add(insightPeriod);
_symbolDataBySymbol[i.Symbol].TradePrice=0;
_symbolDataBySymbol[i.Symbol].MaxPrice=0;
}
}
lastinsights = insights;
return insights;
}
private IEnumerable<Insight> RollAlpha(QCAlgorithm algorithm)
{
var insights = new List<Insight>();
var insightPeriod = _resolution.ToTimeSpan().Multiply(_predictionInterval).Add(new TimeSpan(0,10,0));
//push insights again
foreach (var i in lastinsights)
{
var symbolData = _symbolDataBySymbol[i.Symbol];
if(i.Direction==InsightDirection.Down)
symbolData.MaxPrice = symbolData.MaxPrice==0?algorithm.Securities[i.Symbol].Price:Math.Min(symbolData.MaxPrice,algorithm.Securities[i.Symbol].Price);
else if(i.Direction==InsightDirection.Up)
symbolData.MaxPrice = Math.Max(symbolData.MaxPrice,algorithm.Securities[i.Symbol].Price);
if(IsDateOK(algorithm.Time,_symbolDataBySymbol[i.Symbol].insightDate) )
insights.Add(Insight.Price(i.Symbol, insightPeriod, i.Direction, i.Magnitude, null));
}
lastinsights = insights;
return insights;
}
/// <summary>
/// Event fired each time the we add/remove securities from the data feed
/// </summary>
/// <param name="algorithm">The algorithm instance that experienced the change in securities</param>
/// <param name="changes">The security additions and removals from the algorithm</param>
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
var addedSymbols = new List<Symbol>();
foreach (var added in changes.AddedSecurities)
{
SymbolData symbolData;
if (!_symbolDataBySymbol.TryGetValue(added.Symbol, out symbolData))
{
var ticker = added.Symbol;
var security = algorithm.AddSecurity(added.Symbol.SecurityType, ticker, _resolution);
security.SetLeverage(100);
symbolData = new SymbolData(algorithm, _resolution, security);
symbolData.insightDate = algorithm.Time;
symbolData.Security = added;
algorithm.RegisterIndicator(ticker, symbolData.Skew, _resolution.ToTimeSpan().Multiply(_periods));
algorithm.RegisterIndicator(ticker, symbolData.ROC, _resolution.ToTimeSpan().Multiply(_periods));//_resolution);
_symbolDataBySymbol[added.Symbol] = symbolData;
addedSymbols.Add(added.Symbol);
}
}
foreach (var removed in changes.RemovedSecurities)
{
SymbolData symbolData;
if (!_symbolDataBySymbol.TryGetValue(removed.Symbol, out symbolData))
{
_symbolDataBySymbol.Remove(removed.Symbol);
algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, symbolData.Consolidator);
}
//algorithm.RemoveSecurity(removed.Symbol);
}
if (addedSymbols.Count > 0)
{
// warmup our indicators by pushing history through the consolidators
algorithm.History(addedSymbols, 100, _resolution)
.PushThrough(bar =>
{
SymbolData symbolData;
if (_symbolDataBySymbol.TryGetValue(bar.Symbol, out symbolData))
{
symbolData.ROC.Update(bar.EndTime, bar.Value);
}
});
}
}
private bool IsDateOK(DateTime time, DateTime time2)
{
return time.Subtract(time2).TotalMinutes>=-30;
}
class SymbolData
{
public RateOfChange ROC;
public Security Security { get; set; }
public Symbol Symbol => Security.Symbol;
public SkewIndicator Skew;
public string Ticker;
public readonly IDataConsolidator Consolidator;
public SymbolData(QCAlgorithm algorithm, Resolution resolution, Security security)
{
Ticker = security.Symbol;
Skew = new SkewIndicator(Ticker,100);//251);
ROC = new RateOfChange(Ticker, 20);
Consolidator = algorithm.ResolveConsolidator(security.Symbol, resolution);
algorithm.SubscriptionManager.AddConsolidator(security.Symbol, Consolidator);
}
public decimal _insight_price = 1;
public InsightDirection _insight_dir = InsightDirection.Flat;
public decimal pps = 0;
public DateTime insightDate;
public decimal TradePrice = 0;
public decimal MaxPrice = 0;
public bool IsReady()
{
if (!Skew.IsReady) return false;
return true;
}
public void Reset()
{
}
public double ROCValue()
{
return double.IsNaN((double)ROC.Current.Value)?(double)0d: (double)ROC.Current.Value;
}
}
}
}/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using Accord.Math;
using Python.Runtime;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Scheduling;
namespace QuantConnect.Algorithm.Framework.Portfolio
{
/// <summary>
/// Provides an implementation of Mean-Variance portfolio optimization based on modern portfolio theory.
/// The interval of weights in optimization method can be changed based on the long-short algorithm.
/// The default model uses the last three months daily price to calculate the optimal weight
/// with the weight range from -1 to 1 and minimize the portfolio variance with a target return of 2%
/// </summary>
public class MeanVarianceOptimizationPortfolioConstructionModel2 : PortfolioConstructionModel
{
private readonly int _lookback;
private readonly int _period;
private readonly Resolution _resolution;
private readonly PortfolioBias _portfolioBias;
private readonly IPortfolioOptimizer _optimizer;
private readonly Dictionary<Symbol, ReturnsSymbolData> _symbolDataDict;
/// <summary>
/// Initialize the model
/// </summary>
/// <param name="rebalancingDateRules">The date rules used to define the next expected rebalance time
/// in UTC</param>
/// <param name="portfolioBias">Specifies the bias of the portfolio (Short, Long/Short, Long)</param>
/// <param name="lookback">Historical return lookback period</param>
/// <param name="period">The time interval of history price to calculate the weight</param>
/// <param name="resolution">The resolution of the history price</param>
/// <param name="targetReturn">The target portfolio return</param>
/// <param name="optimizer">The portfolio optimization algorithm. If the algorithm is not provided then the default will be mean-variance optimization.</param>
public MeanVarianceOptimizationPortfolioConstructionModel2(IDateRule rebalancingDateRules,
PortfolioBias portfolioBias = PortfolioBias.Long,
int lookback = 1,
int period = 63,
Resolution resolution = Resolution.Daily,
double targetReturn = 0.02,
IPortfolioOptimizer optimizer = null)
: this(rebalancingDateRules.ToFunc(), portfolioBias, lookback, period, resolution, targetReturn, optimizer)
{
}
/// <summary>
/// Initialize the model
/// </summary>
/// <param name="rebalanceResolution">Rebalancing frequency</param>
/// <param name="portfolioBias">Specifies the bias of the portfolio (Short, Long/Short, Long)</param>
/// <param name="lookback">Historical return lookback period</param>
/// <param name="period">The time interval of history price to calculate the weight</param>
/// <param name="resolution">The resolution of the history price</param>
/// <param name="targetReturn">The target portfolio return</param>
/// <param name="optimizer">The portfolio optimization algorithm. If the algorithm is not provided then the default will be mean-variance optimization.</param>
public MeanVarianceOptimizationPortfolioConstructionModel2(Resolution rebalanceResolution = Resolution.Daily,
PortfolioBias portfolioBias = PortfolioBias.LongShort,
int lookback = 1,
int period = 63,
Resolution resolution = Resolution.Daily,
double targetReturn = 0.02,
IPortfolioOptimizer optimizer = null)
: this(rebalanceResolution.ToTimeSpan(), portfolioBias, lookback, period, resolution, targetReturn, optimizer)
{
}
/// <summary>
/// Initialize the model
/// </summary>
/// <param name="timeSpan">Rebalancing frequency</param>
/// <param name="portfolioBias">Specifies the bias of the portfolio (Short, Long/Short, Long)</param>
/// <param name="lookback">Historical return lookback period</param>
/// <param name="period">The time interval of history price to calculate the weight</param>
/// <param name="resolution">The resolution of the history price</param>
/// <param name="targetReturn">The target portfolio return</param>
/// <param name="optimizer">The portfolio optimization algorithm. If the algorithm is not provided then the default will be mean-variance optimization.</param>
public MeanVarianceOptimizationPortfolioConstructionModel2(TimeSpan timeSpan,
PortfolioBias portfolioBias = PortfolioBias.LongShort,
int lookback = 1,
int period = 63,
Resolution resolution = Resolution.Daily,
double targetReturn = 0.02,
IPortfolioOptimizer optimizer = null)
: this(dt => dt.Add(timeSpan), portfolioBias, lookback, period, resolution, targetReturn, optimizer)
{
}
/// <summary>
/// Initialize the model
/// </summary>
/// <param name="rebalance">Rebalancing func or if a date rule, timedelta will be converted into func.
/// For a given algorithm UTC DateTime the func returns the next expected rebalance time
/// or null if unknown, in which case the function will be called again in the next loop. Returning current time
/// will trigger rebalance. If null will be ignored</param>
/// <param name="portfolioBias">Specifies the bias of the portfolio (Short, Long/Short, Long)</param>
/// <param name="lookback">Historical return lookback period</param>
/// <param name="period">The time interval of history price to calculate the weight</param>
/// <param name="resolution">The resolution of the history price</param>
/// <param name="targetReturn">The target portfolio return</param>
/// <param name="optimizer">The portfolio optimization algorithm. If the algorithm is not provided then the default will be mean-variance optimization.</param>
/// <remarks>This is required since python net can not convert python methods into func nor resolve the correct
/// constructor for the date rules parameter.
/// For performance we prefer python algorithms using the C# implementation</remarks>
public MeanVarianceOptimizationPortfolioConstructionModel2(PyObject rebalance,
PortfolioBias portfolioBias = PortfolioBias.LongShort,
int lookback = 1,
int period = 63,
Resolution resolution = Resolution.Daily,
double targetReturn = 0.02,
IPortfolioOptimizer optimizer = null)
: this((Func<DateTime, DateTime?>)null, portfolioBias, lookback, period, resolution, targetReturn, optimizer)
{
SetRebalancingFunc(rebalance);
}
/// <summary>
/// Initialize the model
/// </summary>
/// <param name="rebalancingFunc">For a given algorithm UTC DateTime returns the next expected rebalance UTC time.
/// Returning current time will trigger rebalance. If null will be ignored</param>
/// <param name="portfolioBias">Specifies the bias of the portfolio (Short, Long/Short, Long)</param>
/// <param name="lookback">Historical return lookback period</param>
/// <param name="period">The time interval of history price to calculate the weight</param>
/// <param name="resolution">The resolution of the history price</param>
/// <param name="targetReturn">The target portfolio return</param>
/// <param name="optimizer">The portfolio optimization algorithm. If the algorithm is not provided then the default will be mean-variance optimization.</param>
public MeanVarianceOptimizationPortfolioConstructionModel2(Func<DateTime, DateTime> rebalancingFunc,
PortfolioBias portfolioBias = PortfolioBias.LongShort,
int lookback = 1,
int period = 63,
Resolution resolution = Resolution.Daily,
double targetReturn = 0.02,
IPortfolioOptimizer optimizer = null)
: this(rebalancingFunc != null ? (Func<DateTime, DateTime?>)(timeUtc => rebalancingFunc(timeUtc)) : null,
portfolioBias,
lookback,
period,
resolution,
targetReturn,
optimizer)
{
}
/// <summary>
/// Initialize the model
/// </summary>
/// <param name="rebalancingFunc">For a given algorithm UTC DateTime returns the next expected rebalance time
/// or null if unknown, in which case the function will be called again in the next loop. Returning current time
/// will trigger rebalance.</param>
/// <param name="portfolioBias">Specifies the bias of the portfolio (Short, Long/Short, Long)</param>
/// <param name="lookback">Historical return lookback period</param>
/// <param name="period">The time interval of history price to calculate the weight</param>
/// <param name="resolution">The resolution of the history price</param>
/// <param name="targetReturn">The target portfolio return</param>
/// <param name="optimizer">The portfolio optimization algorithm. If the algorithm is not provided then the default will be mean-variance optimization.</param>
public MeanVarianceOptimizationPortfolioConstructionModel2(Func<DateTime, DateTime?> rebalancingFunc,
PortfolioBias portfolioBias = PortfolioBias.LongShort,
int lookback = 1,
int period = 63,
Resolution resolution = Resolution.Daily,
double targetReturn = 0.02,
IPortfolioOptimizer optimizer = null)
: base(rebalancingFunc)
{
_lookback = lookback;
_period = period;
_resolution = resolution;
_portfolioBias = portfolioBias;
var lower = portfolioBias == PortfolioBias.Long ? 0 : -1;
var upper = portfolioBias == PortfolioBias.Short ? 0 : 1;
_optimizer = optimizer ?? new MinimumVariancePortfolioOptimizer(lower, upper, targetReturn);
_symbolDataDict = new Dictionary<Symbol, ReturnsSymbolData>();
}
/// <summary>
/// Method that will determine if the portfolio construction model should create a
/// target for this insight
/// </summary>
/// <param name="insight">The insight to create a target for</param>
/// <returns>True if the portfolio should create a target for the insight</returns>
protected override bool ShouldCreateTargetForInsight(Insight insight)
{
var filteredInsight = FilterInvalidInsightMagnitude(Algorithm, new[] { insight }).FirstOrDefault();
if (filteredInsight == null)
{
return false;
}
ReturnsSymbolData data;
if (_symbolDataDict.TryGetValue(insight.Symbol, out data))
{
if (!insight.Magnitude.HasValue)
{
Algorithm.SetRunTimeError(
new ArgumentNullException(
insight.Symbol.Value,
"MeanVarianceOptimizationPortfolioConstructionModel does not accept 'null' as Insight.Magnitude. " +
"Please checkout the selected Alpha Model specifications: " + insight.SourceModel));
return false;
}
data.Add(Algorithm.Time, insight.Magnitude.Value.SafeDecimalCast());
}
return true;
}
/// <summary>
/// Will determine the target percent for each insight
/// </summary>
/// <param name="activeInsights">The active insights to generate a target for</param>
/// <returns>A target percent for each insight</returns>
protected override Dictionary<Insight, double> DetermineTargetPercent(List<Insight> activeInsights)
{
var targets = new Dictionary<Insight, double>();
// Get the last generated active insight for each symbol
var lastActiveInsights = from insight in activeInsights
group insight by insight.Symbol into g
select g.OrderBy(x => x.GeneratedTimeUtc).Last();
var symbols = lastActiveInsights.Where(x=> x.Direction !=InsightDirection.Flat).Select(x => x.Symbol).ToList();
// Get symbols' returns
var returns = _symbolDataDict.FormReturnsMatrix(symbols);
// Calculate rate of returns
var rreturns = returns.Apply(e => Math.Pow(1.0 + e, 252.0) - 1.0);
// The optimization method processes the data frame
var w = _optimizer.Optimize(rreturns);
// process results
if (w.Length > 0)
{
var sidx = 0;
foreach (var symbol in symbols)
{
double weight = 0;
if(sidx<w.Length) weight = w[sidx];
if(double.IsNaN(weight))
{
weight = 0;
}
// don't trust the optimizer
else if (_portfolioBias != PortfolioBias.LongShort
&& Math.Sign(weight) != (int)_portfolioBias)
{
weight = 0;
}
var insightSimbol = activeInsights.First(insight => insight.Symbol == symbol);
targets[insightSimbol] = (int)insightSimbol.Direction * Math.Abs(weight) *
(int)((insightSimbol.Direction==InsightDirection.Up)?
QuantConnect.Algorithm.CSharp.SkewnessCommoditiesAlgo.WeightMultiplierLong:
QuantConnect.Algorithm.CSharp.SkewnessCommoditiesAlgo.WeightMultiplierShort);
sidx++;
}
}
symbols = lastActiveInsights.Where(x=> x.Direction ==InsightDirection.Flat).Select(x => x.Symbol).ToList();
foreach (var symbol in symbols)
{
targets[activeInsights.First(insight => insight.Symbol == symbol)] = 0;
}
return targets;
}
/// <summary>
/// Event fired each time the we add/remove securities from the data feed
/// </summary>
/// <param name="algorithm">The algorithm instance that experienced the change in securities</param>
/// <param name="changes">The security additions and removals from the algorithm</param>
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
base.OnSecuritiesChanged(algorithm, changes);
// clean up data for removed securities
foreach (var removed in changes.RemovedSecurities)
{
ReturnsSymbolData data;
if (_symbolDataDict.TryGetValue(removed.Symbol, out data))
{
_symbolDataDict.Remove(removed.Symbol);
}
}
if (changes.AddedSecurities.Count == 0)
return;
// initialize data for added securities
foreach (var added in changes.AddedSecurities)
{
if (!_symbolDataDict.ContainsKey(added.Symbol))
{
var symbolData = new ReturnsSymbolData(added.Symbol, _lookback, _period);
_symbolDataDict[added.Symbol] = symbolData;
}
}
// warmup our indicators by pushing history through the consolidators
algorithm.History(changes.AddedSecurities.Select(security => security.Symbol), _lookback * _period, _resolution)
.PushThrough(bar =>
{
ReturnsSymbolData symbolData;
if (_symbolDataDict.TryGetValue(bar.Symbol, out symbolData))
{
symbolData.Update(bar.EndTime, bar.Value);
}
});
}
}
}/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Linq;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Data.UniverseSelection;
namespace QuantConnect.Algorithm.Framework.Execution
{
/// <summary>
/// Provides an implementation of <see cref="IExecutionModel"/> that immediately submits
/// market orders to achieve the desired portfolio targets
/// </summary>
public class ImmediateExecutionModel2 : ExecutionModel
{
private readonly PortfolioTargetCollection _targetsCollection = new PortfolioTargetCollection();
/// <summary>
/// Immediately submits orders for the specified portfolio targets.
/// </summary>
/// <param name="algorithm">The algorithm instance</param>
/// <param name="targets">The portfolio targets to be ordered</param>
public override void Execute(QCAlgorithm algorithm, IPortfolioTarget[] targets)
{
_targetsCollection.AddRange(targets);
foreach (var target in _targetsCollection.OrderByMarginImpact(algorithm))
{
// calculate remaining quantity to be ordered
var quantity = OrderSizing.GetUnorderedQuantity(algorithm, target);
/*
var existing = algorithm.Securities[target.Symbol].Holdings.Quantity
+ algorithm.Transactions.GetOpenOrders(target.Symbol)
.Aggregate(0m, (d, order) => d + order.Quantity);
var quantity = target.Quantity - existing;
*/
var lastData = algorithm.Securities[target.Symbol].GetLastData();
if (quantity != 0 && Math.Abs(algorithm.Time.Subtract ( lastData.EndTime ).TotalMinutes)<5 && algorithm.IsMarketOpen(target.Symbol))
{
algorithm.MarketOrder(target.Symbol, quantity);
}
}
_targetsCollection.ClearFulfilled(algorithm);
}
/// <summary>
/// Event fired each time the we add/remove securities from the data feed
/// </summary>
/// <param name="algorithm">The algorithm instance that experienced the change in securities</param>
/// <param name="changes">The security additions and removals from the algorithm</param>
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
}
}
}using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Data.Custom.CBOE;
using System.Collections.Concurrent;
namespace QuantConnect.Algorithm.CSharp
{
public class SkewnessCommoditiesAlgo : QCAlgorithm
{
public static int WeightMultiplierLong = 2; //use 1 if no leverage
public static int WeightMultiplierShort = 2; //use 1 if no leverage
public Symbol cboeVix;
public decimal vix;
public IEnumerable<Symbol> symbols;
public RateOfChange vixROC;
Resolution resolution = Resolution.Minute;
int periods =1440;
public override void Initialize()
{
//Start and End Date range for the backtest:
SetStartDate(2000, 1, 1);
SetEndDate(2020, 7, 20);
SetCash(10000);
SetBenchmark("SPY");
cboeVix = AddData<CBOE>("VIX", Resolution.Daily).Symbol;
SetAlpha(new AlphaSkew(resolution, periods));
vixROC = new RateOfChange(cboeVix, 9);
RegisterIndicator(cboeVix, vixROC, Resolution.Daily);
SetExecution(new ImmediateExecutionModel2());
SetPortfolioConstruction(new MeanVarianceOptimizationPortfolioConstructionModel2( timeSpan:new TimeSpan(1,0,0), portfolioBias: PortfolioBias.LongShort,optimizer:new MaximumSharpeRatioPortfolioOptimizer()));
AddUniverseSelection(new ManualUniverseSelectionModel(
QuantConnect.Symbol.Create("BCOUSD", SecurityType.Cfd, Market.Oanda),
//QuantConnect.Symbol.Create("WTIUSD", SecurityType.Cfd, Market.Oanda),
QuantConnect.Symbol.Create("XAGUSD", SecurityType.Cfd, Market.Oanda),
QuantConnect.Symbol.Create("XAUUSD", SecurityType.Cfd, Market.Oanda),
QuantConnect.Symbol.Create("XCUUSD", SecurityType.Cfd, Market.Oanda),
QuantConnect.Symbol.Create("SOYBNUSD", SecurityType.Cfd, Market.Oanda),
QuantConnect.Symbol.Create("WHEATUSD", SecurityType.Cfd, Market.Oanda),
QuantConnect.Symbol.Create("CORNUSD", SecurityType.Cfd, Market.Oanda),
QuantConnect.Symbol.Create("XPTUSD", SecurityType.Cfd, Market.Oanda),
QuantConnect.Symbol.Create("CORNUSD", SecurityType.Cfd, Market.Oanda),
QuantConnect.Symbol.Create("NATGASUSD", SecurityType.Cfd, Market.Oanda),
QuantConnect.Symbol.Create("XPDUSD", SecurityType.Cfd, Market.Oanda),
QuantConnect.Symbol.Create("SUGARUSD", SecurityType.Cfd, Market.Oanda)
));
SetBrokerageModel(QuantConnect.Brokerages.BrokerageName.OandaBrokerage);
//either use this risk or the rollover alphas managed by alphaskew
//AddRiskManagement(new MaximumUnrealizedProfitPercentPerSecurity(0.02m));
//AddRiskManagement(new MaximumDrawdownPercentPerSecurity(0.01m));
}
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// Slice object keyed by symbol containing the stock data
public override void OnData(Slice data)
{
if (data.ContainsKey(cboeVix))
{
vix = data.Get<CBOE>(cboeVix).Close;
if(vix>1)
vixROC.Update(new IndicatorDataPoint(data.Get<CBOE>(cboeVix).Time, data.Get<CBOE>(cboeVix).Close));
}
}
}
}