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