Overall Statistics |
Total Trades 5 Average Win 4.94% Average Loss -2.74% Compounding Annual Return -6.888% Drawdown 2.100% Expectancy -0.066 Net Profit -0.740% Sharpe Ratio -0.791 Loss Rate 67% Win Rate 33% Profit-Loss Ratio 1.80 Alpha -0.156 Beta 6.711 Annual Standard Deviation 0.067 Annual Variance 0.004 Information Ratio -1.022 Tracking Error 0.067 Treynor Ratio -0.008 Total Fees $26.25 |
namespace net.phobot.quant { public class ExecutionData { public decimal Price { get; set; } public decimal Quantity { get; set; } } public class MyExecutionModel : ExecutionModel { private static decimal LEG_PRICE_LOWER_LIMIT = 0.03M; private readonly Dictionary<Symbol, Security> _symbolData; private Dictionary<DateTime, IPortfolioTarget[]> _targetsCollection; public MyExecutionModel() { _symbolData = new Dictionary<Symbol, Security>(); _targetsCollection = new Dictionary<DateTime, IPortfolioTarget[]>(); } public override void Execute(QCAlgorithmFramework algorithm, IPortfolioTarget[] targets) { var prices_by_symbol = new Dictionary<Symbol,Dictionary<Symbol,ExecutionData>>(); foreach (var target in targets) { var existing = algorithm.Securities[target.Symbol].Holdings.Quantity + algorithm.Transactions.GetOpenOrders(target.Symbol).Sum(o => o.Quantity); var quantity = target.Quantity - existing; if (quantity != 0) { var limit_price = 0.0m; if (target.Symbol.EndsWith("181019C00034000")) { limit_price = 2.35m; } if (target.Symbol.EndsWith("181019C00036000")) { limit_price = 1.20m; } if (target.Symbol.HasUnderlying) { var underlying = target.Symbol.Underlying; if(! prices_by_symbol.ContainsKey(underlying)) { prices_by_symbol[underlying] = new Dictionary<Symbol,ExecutionData>(); } prices_by_symbol[underlying][target.Symbol] = new ExecutionData{ Price = limit_price, Quantity = quantity}; } else { if (Math.Abs(limit_price) < LEG_PRICE_LOWER_LIMIT) { algorithm.LimitOrder(target.Symbol, quantity, limit_price); } } } } foreach (var underlying in prices_by_symbol.Keys) { var legs = prices_by_symbol[underlying]; if(legs.Values.Select(data => data.Price).Where(price => Math.Abs(price) < LEG_PRICE_LOWER_LIMIT).Any()) { continue; } foreach (var leg_symbol in legs.Keys) { var execution_data = legs[leg_symbol]; algorithm.LimitOrder(leg_symbol, execution_data.Quantity, execution_data.Price); var log_msg = $"Entered limit order for {execution_data.Quantity} contracts of {leg_symbol} at price {execution_data.Price}"; Security security; if (_symbolData.TryGetValue(leg_symbol, out security)) { log_msg += $" Bid: {security.BidPrice} Ask: {security.AskPrice}"; } algorithm.Log(log_msg); } } } public override void OnSecuritiesChanged(QCAlgorithmFramework algorithm, SecurityChanges changes) { foreach (var added in changes.AddedSecurities) { if (!_symbolData.ContainsKey(added.Symbol)) { _symbolData[added.Symbol] = added; } } foreach (var removed in changes.RemovedSecurities) { if (_symbolData.ContainsKey(removed.Symbol) && IsSafeToRemove(algorithm, removed.Symbol)) { _symbolData.Remove(removed.Symbol); } } } protected virtual bool IsSafeToRemove(QCAlgorithmFramework algorithm, Symbol symbol) { // confirm the security isn't currently a member of any universe return !algorithm.UniverseManager.Any(kvp => kvp.Value.ContainsMember(symbol)); } } }
namespace net.phobot.quant { public class MyPortfolioConstructionModel : PortfolioConstructionModel { public override IEnumerable<IPortfolioTarget> CreateTargets(QCAlgorithmFramework algorithm, Insight[] insights) { var number_of_contracts = 21; return insights.Select(insight => new PortfolioTarget(insight.Symbol, ((int) insight.Direction * number_of_contracts))); } } }
using QuantConnect.Securities.Option; namespace net.phobot.quant { public class MyAlphaModel : AlphaModel { List<Security> _securities = new List<Security>(); public override void OnSecuritiesChanged(QCAlgorithmFramework algorithm, SecurityChanges changes) { foreach(var added in changes.AddedSecurities) { _securities.Add(added); } foreach(var removed in changes.RemovedSecurities) { _securities.RemoveAll(item => item.Equals(removed)); } } public override IEnumerable<Insight> Update(QCAlgorithmFramework algorithm, Slice data) { var insights = new List<Insight>(); var date_str = algorithm.Time.ToString("yyyy-MM-dd HH:mm"); if (date_str.Equals("2018-09-18 09:31")) { foreach (var security in _securities) { if (security.Symbol.EndsWith("181019C00034000")) { insights.Add(new Insight(security.Symbol, new TimeSpan(6, 30, 0), InsightType.Price, InsightDirection.Down)); } if (security.Symbol.EndsWith("181019C00036000")) { insights.Add(new Insight(security.Symbol, new TimeSpan(6, 30, 0), InsightType.Price, InsightDirection.Up)); } } } // If we've been assigned or have exercised and are holding stock, liquidate the entire position: foreach (var underlying_symbol in UnderlyingsOfHoldings(algorithm)) { var equity_holdings = EquityHoldings(underlying_symbol, algorithm); if (equity_holdings.Any()) { var option_holdings = OptionHoldingsMatching(underlying_symbol, algorithm); LiquidatePosition(option_holdings, algorithm); LiquidateEquity(underlying_symbol, algorithm); } } return insights; } private IEnumerable<Symbol> UnderlyingsOfHoldings(QCAlgorithmFramework algorithm) { var option_underlyings = algorithm.Securities.Keys .Where(symbol => symbol.HasUnderlying) .Where(symbol => algorithm.Securities[symbol].Holdings.Quantity != 0) .Select(symbol => symbol.Underlying); var underlying_symbols = new HashSet<Symbol>(option_underlyings); var equity_holdings = algorithm.Securities.Keys .Where(symbol => ! symbol.HasUnderlying) .Where(symbol => algorithm.Securities[symbol].Holdings.Quantity != 0); var equity_symbols = new HashSet<Symbol>(equity_holdings); underlying_symbols.UnionWith(equity_symbols); return underlying_symbols; } private IEnumerable<OptionHolding> OptionHoldingsMatching(Symbol equity_symbol, QCAlgorithmFramework algorithm) { var holdings = algorithm.Securities.Keys .Where(symbol => symbol.HasUnderlying) .Where(symbol => symbol.Underlying.Value.Equals(equity_symbol.Value)) .Where(symbol => algorithm.Securities[symbol].Holdings.Quantity != 0) .Select(symbol => (OptionHolding) algorithm.Securities[symbol].Holdings); return holdings; } private IEnumerable<SecurityHolding> EquityHoldings(Symbol equity_symbol, QCAlgorithmFramework algorithm) { var holdings = algorithm.Securities.Keys .Where(symbol => ! symbol.HasUnderlying) .Where(symbol => symbol.Value.Equals(equity_symbol.Value)) .Where(symbol => algorithm.Securities[symbol].Holdings.Quantity != 0) .Select(symbol => algorithm.Securities[symbol].Holdings); return holdings; } private void LiquidatePosition(IEnumerable<SecurityHolding> security_holdings, QCAlgorithmFramework algorithm) { foreach (var holding in security_holdings) { algorithm.RemoveSecurity(holding.Symbol); } } private void LiquidateEquity(Symbol symbol, QCAlgorithmFramework algorithm) { // algorithm.RemoveSecurity(symbol); algorithm.SetHoldings(symbol, 0); } } }
namespace net.phobot.quant { static class ExtensionMethods { public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dict, K key) { return dict.GetValueOrDefault(key, default(V)); } public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dict, K key, V defVal) { V value; return dict.TryGetValue(key, out value) ? value : defVal; } public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dict, K key, Func<V> defValSelector) { V value; return dict.TryGetValue(key, out value) ? value : defValSelector(); } } }
namespace net.phobot.quant { public class SchaefferCs : QCAlgorithm { public override void Initialize() { SetStartDate(2018, 9, 11); SetEndDate(2018, 10, 18); SetCash(100000); UniverseSettings.Resolution = Resolution.Hour; SetUniverseSelection(new MyOptionUniverseSelectionModel()); SetAlpha(new MyAlphaModel()); SetPortfolioConstruction(new MyPortfolioConstructionModel()); SetExecution(new MyExecutionModel()); SetRiskManagement(new NullRiskManagementModel()); } } }
namespace net.phobot.quant { public class MyOptionUniverseSelectionModel : FundamentalUniverseSelectionModel { public MyOptionUniverseSelectionModel( Boolean filterFineData = true, UniverseSettings universeSettings = null, ISecurityInitializer securityInitializer = null): base(filterFineData, universeSettings, securityInitializer) { } public override IEnumerable<Symbol> SelectCoarse(QCAlgorithmFramework algorithm, IEnumerable<CoarseFundamental> coarse) { var filtered = coarse .Where(asset => asset.Symbol.Value.Equals("TRN")) .Select(asset => asset.Symbol); return filtered; } public override IEnumerable<Symbol> SelectFine(QCAlgorithmFramework algorithm, IEnumerable<FineFundamental> fine) { var current_date = NextTradingDay(algorithm); var equity_symbols = fine.Select(asset => asset.Symbol); var symbols_to_return = new List<Symbol>(equity_symbols); foreach (Symbol equity_symbol in equity_symbols) { var symbol_string = equity_symbol.Value; var equity = algorithm.AddEquity(symbol_string); equity.SetDataNormalizationMode(DataNormalizationMode.Raw); // Remove warning messages var contracts = algorithm.OptionChainProvider .GetOptionContractList(equity_symbol, current_date) .Where(symbol => symbol.EndsWith("181019C00034000") || symbol.EndsWith("181019C00036000")) .OrderBy(symbol => symbol.ID.StrikePrice) .ToList(); if(contracts.Count() == 0) { continue; } var short_option = contracts[0]; algorithm.AddOptionContract(short_option); symbols_to_return.Add(short_option); var long_option = contracts[1]; algorithm.AddOptionContract(long_option); symbols_to_return.Add(long_option); } return symbols_to_return; } private DateTime NextTradingDay(QCAlgorithmFramework algorithm) { var tomorrow = algorithm.Time.AddDays(1); var five_days_after = tomorrow.AddDays(5); var next_trading_days = algorithm.TradingCalendar.GetDaysByType(TradingDayType.BusinessDay, tomorrow, five_days_after); return next_trading_days.First().Date; } } }