Overall Statistics |
Total Trades 23008 Average Win 0.52% Average Loss -0.45% Compounding Annual Return 322.531% Drawdown 70.300% Expectancy 0.157 Net Profit 110450.360% Sharpe Ratio 3.194 Probabilistic Sharpe Ratio 93.394% Loss Rate 47% Win Rate 53% Profit-Loss Ratio 1.16 Alpha 3.043 Beta 0.269 Annual Standard Deviation 0.96 Annual Variance 0.922 Information Ratio 3.079 Tracking Error 0.968 Treynor Ratio 11.38 Total Fees $2756848.24 Estimated Strategy Capacity $8000000.00 Lowest Capacity Asset PINS X3RPXTZRW09X |
#region imports using System; using System.Collections.Generic; using System.Linq; using QuantConnect.Algorithm.Framework.Selection; using QuantConnect.Util; using QuantConnect.Indicators; using QuantConnect.Data; using QuantConnect.Data.Fundamental; using QuantConnect.Data.Market; using QuantConnect.Data.UniverseSelection; using QuantConnect.Orders.Fees; using QuantConnect.Scheduling; using QuantConnect.Securities; #endregion namespace QuantConnect.Algorithm.CSharp { public class Flock : QCAlgorithm { List<Symbol> HighDollarVolumeStocks = new List<Symbol>(); int _coarse_count = 250; int _stocks_to_hold = 10; int _period = 5; decimal Leverage = 0.99m; decimal Threshold = 0.0m; private bool _selection_flag = false; private Dictionary<Symbol, RollingWindow<decimal>> _data = new Dictionary<Symbol, RollingWindow<decimal>>(); private Dictionary<Symbol, float> _weight = new Dictionary<Symbol, float>(); private Dictionary<Symbol, decimal> _price = new Dictionary<Symbol, decimal>(); public override void Initialize() { UniverseSettings.Resolution = Resolution.Minute; SetStartDate(2018, 1, 1); SetCash(100000); AddUniverseSelection(new FineFundamentalUniverseSelectionModel(CoarseSelectionFunction, FineSelectionFunction)); Symbol symbol = AddEquity("SPY", Resolution.Minute).Symbol; SetSecurityInitializer((Security security) => security.SetMarketPrice(GetLastKnownPrice(security))); // selection lambda function Schedule.On(DateRules.MonthStart(symbol), TimeRules.AfterMarketOpen(symbol), () => { _selection_flag = true; }); } public override void OnSecuritiesChanged(SecurityChanges changes) { foreach (Security security in changes.AddedSecurities){ security.SetFeeModel(new CustomFeeModel()); security.SetLeverage(10); security.SetMarketPrice(GetLastKnownPrice(security)); } // liquidate first Symbol[] invested = (from x in Portfolio where x.Value.Invested select x.Key).ToArray(); foreach (Symbol symbol in invested) if (!_weight.ContainsKey(symbol)) MarketOnOpenOrder(symbol, -Portfolio[symbol].Quantity); // Liquidate(symbol); // trade execution foreach (KeyValuePair<Symbol, float> item in _weight) { // SetHoldings(item.Key, item.Value); decimal q = (Portfolio.TotalPortfolioValue * (decimal)item.Value) / _price[item.Key]; //#data[item.Key].Value; MarketOnOpenOrder(item.Key, q); } _weight.Clear(); _price.Clear(); } IEnumerable<Symbol> CoarseSelectionFunction(IEnumerable<CoarseFundamental> coarse) { // store daily stock prices foreach(CoarseFundamental stock in coarse){ Symbol symbol = stock.Symbol; if (_data.ContainsKey(symbol)) _data[symbol].Add(stock.AdjustedPrice); } // if (!_selection_flag) // return Universe.Unchanged; Symbol[] selected = coarse.Where(x=> x.Symbol.Value != "AMC" && x.Symbol.Value != "GME" && x.Symbol.Value != "UVXY").OrderByDescending(x=>x.DollarVolume).Select(x=>x.Symbol).Take(_coarse_count).ToArray<Symbol>(); foreach (Symbol symbol in selected){ if (_data.ContainsKey(symbol)) continue; _data[symbol] = new RollingWindow<decimal>((int)_period); IEnumerable<TradeBar> history = History<TradeBar>(symbol, _period, Resolution.Daily); if (history.IsNullOrEmpty()){ Log($"Not enough data for {symbol} yet"); continue; } foreach (TradeBar bar in history) { _data[symbol].Add(bar.Close); } // TEST // IEnumerable<TradeBar> m_history = History<TradeBar>(symbol, _period, Resolution.Minute); } return selected.Where(x=>_data[x].IsReady).ToList<Symbol>(); } IEnumerable<Symbol> FineSelectionFunction(IEnumerable<FineFundamental> fine) { // List<Symbol> fine_symbols = fine.Select(x=>x.Symbol).ToList<Symbol>(); Dictionary<Symbol, decimal> avg_ratio = new Dictionary<Symbol, decimal>(); foreach (FineFundamental stock1 in fine) { Symbol symbol1 = stock1.Symbol; decimal[] prices1 = _data[symbol1].ToArray<decimal>(); decimal averagePrice1 = prices1.Average(); decimal[] normalizedPrices1 = prices1.Select(x => x / averagePrice1).ToArray(); decimal sumRatios = 0; foreach (FineFundamental stock2 in fine) { Symbol symbol2 = stock2.Symbol; if (symbol1 != symbol2) { decimal[] prices2 = _data[symbol2].ToArray<decimal>(); decimal averagePrice2 = prices2.Average(); decimal[] normalizedPrices2 = prices2.Select(x => x / averagePrice2).ToArray(); decimal[] differences = normalizedPrices1.Zip(normalizedPrices2, (x, y) => x - y).ToArray(); decimal maxDifference = differences.Max(); decimal minDifference = differences.Min(); decimal differenceRange = maxDifference - minDifference; decimal currentDifference = normalizedPrices1.First() - normalizedPrices2.First(); if (differenceRange != 0) { decimal ratio = currentDifference / differenceRange; sumRatios += ratio; } } } decimal avg_ratio_value = sumRatios / (fine.Count() - 1); if (avg_ratio_value != 0) { avg_ratio[symbol1] = avg_ratio_value; _price[symbol1] = prices1.First(); } } Symbol[] _long = new Symbol[] {}; if (avg_ratio.Count >= _stocks_to_hold) { _long = avg_ratio.OrderByDescending(x => Math.Abs(x.Value)).ToArray().Take(_stocks_to_hold).Select(x=>x.Key).ToArray<Symbol>(); foreach(Symbol symbol in _long) { if (avg_ratio[symbol] < 0) _weight[symbol] = 1.0f / (float)(_long.Count()); else if (avg_ratio[symbol] > 0) _weight[symbol] = -1.0f / (float)(_long.Count()); } } return _weight.Keys; } public void OnData(TradeBars data) { return; // liquidate first // Symbol[] invested = (from x in Portfolio where x.Value.Invested select x.Key).ToArray(); // foreach (Symbol symbol in invested) // if (!_weight.ContainsKey(symbol)) // Liquidate(symbol); // // trade execution // foreach (KeyValuePair<Symbol, float> item in _weight) // if(data.ContainsKey(item.Key)) // { // // SetHoldings(item.Key, item.Value); // decimal q = (Portfolio.TotalPortfolioValue * (decimal)item.Value) / data[item.Key].Value; // MarketOnOpenOrder(item.Key, q); // } // _weight.Clear(); } } public class CustomFeeModel : FeeModel { public override OrderFee GetOrderFee(OrderFeeParameters parameters) { // custom fee math var fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005m; return new OrderFee(new CashAmount(fee, "USD")); } } }