Overall Statistics |
Total Trades 809 Average Win 2.62% Average Loss -1.48% Compounding Annual Return 37.982% Drawdown 24.600% Expectancy 0.391 Net Profit 786.229% Sharpe Ratio 1.638 Loss Rate 50% Win Rate 50% Profit-Loss Ratio 1.77 Alpha 0.333 Beta 0.017 Annual Standard Deviation 0.209 Annual Variance 0.044 Information Ratio -0.266 Tracking Error 0.654 Treynor Ratio 19.811 Total Fees $34869.75 |
using QuantConnect.Data.Market; using QuantConnect.Securities; using System; using System.Collections.Generic; using QuantConnect.Orders; using QuantConnect.Orders.Slippage; using QuantConnect.Indicators; using QuantConnect.Data; using System.Collections.Concurrent; using QuantConnect.Securities.Interfaces; namespace QuantConnect.Algorithm.CSharp { //QC adaption of QT algorithm from https://www.quantopian.com/posts/yavols-yet-another-volatility-strategy-xiv-sniper-using-rsi2 //credit to Kory Hoang and Cesar Alvarez for original version //apologies for messy code, copied some bits from other project when starting out and I don't want //to spend a lot of time cleaning it public sealed partial class VixRsiAlgorithm : FixedSetHoldingsAlgorithm { private const string _algoID = "vixrsi"; private const decimal _securityLeverage = 2; //set per Security, in this case equal to IB intraday limits private const Resolution _resolution = Resolution.Minute; private const bool _disableRealisticFills = true; //you will notice when you tune this up that the algo doesn't look that great, //on the other hand slippage for TLT might be exaggerated, //you might be able to achieve better results by using limit orders in reality private const decimal SLIPPAGE = 0.00m / 100m; public override void Initialize() { SetCash(100000); SetStartDate(2011, 1, 1); //SetEndDate(2017, 1, 1); //SetEndDate(2016, 1, 10); //SetStartDate(2005, 11, 1); //SetEndDate(2016, 10, 01); try { ActualInitialization(); } catch (Exception e) { ReportException(e, this); throw; } } public static void ReportException(Exception e, QCAlgorithm algo) { algo.Error(algo.Time + ": " + e.Message + "\n" + e.StackTrace); algo.Log(algo.Time + ": " + e.Message + "\n" + e.StackTrace); } private readonly List<Tradable> _tradables = new List<Tradable>(); private void ActualInitialization() { Schedule.On(Schedule.DateRules.EveryDay(), Schedule.TimeRules.At(0, 0, 0), AtMidnight); SetBrokerageModel(Brokerages.BrokerageName.InteractiveBrokersBrokerage); _tradables.Add(new Tradable(this, "XIV", "TLT")); Schedule.On(DateRules.EveryDay(_tradables[0].Symbol), TimeRules.AfterMarketOpen(_tradables[0].Symbol, -1), BeforeOpen); Schedule.On(DateRules.EveryDay(_tradables[0].Symbol), TimeRules.BeforeMarketClose(_tradables[0].Symbol, 0.92), RebalanceBeforeClose); SetBenchmark(_tradables[0].Symbol); if (LiveMode) { Schedule.On(DateRules.EveryDay(), TimeRules.Every(TimeSpan.FromMinutes(1)), CheckOrderEvents); } } public override void OnEndOfAlgorithm() { CheckOrderEvents(); //_paramSetPollingThread.Cancel(); //_paramSetPollingThread.Join(); } private void AtMidnight() { //Xtend.DiscardScheduledEvents(); } private void BeforeOpen() { foreach (var tradable in _tradables) { tradable.BeforeOpen(); } } public void OnWarmupData(Slice slice) { //OnData(slice); } private void RebalanceBeforeClose() { foreach (var tradable in _tradables) { tradable.RebalanceBeforeClose(); } } public override void OnData(Slice slice) { CheckOrderEvents(); foreach (var kv in slice.Bars) { var tradable = _tradables.Find(x => x.Symbol == kv.Key); if (tradable != null) { tradable.OnData(kv.Value); } } } private readonly ConcurrentQueue<OrderEvent> _orderEvents = new ConcurrentQueue<OrderEvent>(); public override void OnOrderEvent(OrderEvent ev) { _orderEvents.Enqueue(ev.Clone()); } private void CheckOrderEvents() { for (;;) { OrderEvent ev; if (!_orderEvents.TryDequeue(out ev)) break; var tradable = _tradables.Find(x => x.Symbol == ev.Symbol); if (tradable != null) { tradable.OnOrderEvent(ev); } } } private sealed class Tradable { private readonly VixRsiAlgorithm _algo; public readonly Security Security; public readonly Security SafeSecurity; private readonly TickFillSource _tickFillSource; private readonly SimpleMovingAverage _averageSlippage = new SimpleMovingAverage(200); private readonly SimpleMovingAverage _averageOrderLatency = new SimpleMovingAverage(200); private readonly Maximum _maxOrderLatency = new Maximum(200); private readonly RelativeStrengthIndex _rsi7 = new RelativeStrengthIndex(7); private readonly RelativeStrengthIndex _rsi2 = new RelativeStrengthIndex(2); private decimal _oldRsi7; private decimal _oldRsi2; private bool _nextDayBuy; private bool _nextDaySell; private decimal _takeProfitPrice; private decimal _takeLossPrice; public Symbol Symbol { get { return Security.Symbol; } } public Tradable(VixRsiAlgorithm algo, string symbol, string invSymbol) { _algo = algo; Security = algo.AddSecurity(SecurityType.Equity, symbol, _resolution, true, _securityLeverage, false); if (invSymbol != null) SafeSecurity = algo.AddSecurity(SecurityType.Equity, invSymbol, _resolution, true, _securityLeverage, false); else SafeSecurity = null; if (_disableRealisticFills) Security.SlippageModel = new ConstantSlippageModel(SLIPPAGE); _tickFillSource = new TickFillSource(Symbol); if (!_disableRealisticFills) { var fillModel = new ImmediateWhenVolumeFillModel(algo); //fillModel.TickFillSource = _tickFillSource; fillModel.HighlyLiquidAsset = true; fillModel.OrderDelay = TimeSpan.FromSeconds(1); Security.FillModel = fillModel; } Security.DataFilter = new CustomDataFilter(); } private class CustomDataFilter : ISecurityDataFilter { public bool Filter(Security vehicle, BaseData data) { if (data.DataType == MarketDataType.Tick) { var tick = (Tick)data; if (tick.Suspicious) return false; } return true; } } private bool CanBeInMarket(DateTime now) { return true; } public void OnData(TradeBar bar) { if (Security.HoldStock) { if (Security.Price > _takeProfitPrice || Security.Price <_takeLossPrice) { _nextDaySell = false; Exit(); } } } public void RebalanceBeforeClose() { _rsi2.Update(_algo.Time, Security.Price); _rsi7.Update(_algo.Time, Security.Price); const decimal trigger1 = 25; const decimal trigger2 = 75; if (_rsi7 > trigger1 && _oldRsi7 < trigger1 && !Security.HoldStock) { Enter(); } else if (_rsi2 > trigger2 && _oldRsi2 < trigger2 && !Security.HoldStock) { _nextDayBuy = true; } else if (Security.HoldStock && _rsi2 < trigger2 && _oldRsi2 > trigger2) { _nextDaySell = true; } _oldRsi2 = _rsi2; _oldRsi7 = _rsi7; } private void Enter() { //auto converted to market on open if outside market hours _takeLossPrice = Security.Price * 0.98m; _takeProfitPrice = Security.Price * 1.05m; _algo.Liquidate(SafeSecurity.Symbol); _algo.FixedSetHoldings(Security.Symbol, 1); } private void Exit() { //auto converted to market on open if outside market hours _algo.Liquidate(Security.Symbol); _algo.FixedSetHoldings(SafeSecurity.Symbol, 1); } public void BeforeOpen() { if (!_algo.LiveMode) UpdateOrderStats(); if (_nextDayBuy) { _nextDayBuy = false; if (!Security.HoldStock) Enter(); } if (_nextDaySell) { _nextDaySell = false; if (Security.HoldStock) Exit(); } } private decimal GetExpectedOrderLatency() { if (_averageOrderLatency.Samples != 0) return _averageOrderLatency; return 1; } private void UpdateOrderStats() { var negativeSlippage = -_averageSlippage.Current.Value; _algo.SetRuntimeStatistic("Slippage", negativeSlippage.ToString("P3")); _algo.SetRuntimeStatistic("Latency", _averageOrderLatency.Current.Value.ToString("F2")); _algo.SetRuntimeStatistic("LatencyMax", _maxOrderLatency.Current.Value.ToString("F2")); } private void HandleOrderFilled(OrderEvent ev) { } public void OnOrderEvent(OrderEvent ev) { switch (ev.Status) { case OrderStatus.Invalid: _algo.Debug("Order error: " + ev.Message); _algo.Debug("Order error for " + Symbol.ToString() + ": " + ev.Status); break; //TODO: handle error in some way, maybe retry after a while? case OrderStatus.Filled: HandleOrderFilled(ev); break; } } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace QuantConnect.Algorithm.CSharp { public static class XMath { public static bool IsPowerOfTwo(ulong x) { return (x & (x - 1)) == 0; } public static int Log2(int v) { int r = 0xFFFF - v >> 31 & 0x10; v >>= r; int shift = 0xFF - v >> 31 & 0x8; v >>= shift; r |= shift; shift = 0xF - v >> 31 & 0x4; v >>= shift; r |= shift; shift = 0x3 - v >> 31 & 0x2; v >>= shift; r |= shift; r |= (v >> 1); return r; } public static void Clamp<T>(ref T val, T min, T max) where T : IComparable { if (min.CompareTo(val) > 0) val = min; else if (max.CompareTo(val) < 0) val = max; } } }
using QuantConnect.Algorithm; using QuantConnect.Orders; using QuantConnect.Securities; using System; namespace QuantConnect { public abstract class FixedSetHoldingsAlgorithm : QCAlgorithm { /// <summary> /// Alias for SetHoldings to avoid the M-decimal errors. /// </summary> /// <param name="symbol">string symbol we wish to hold</param> /// <param name="percentage">double percentage of holdings desired</param> /// <param name="liquidateExistingHoldings">liquidate existing holdings if neccessary to hold this stock</param> /// <seealso cref="MarketOrder"/> public void FixedSetHoldings(Symbol symbol, double percentage, bool liquidateExistingHoldings = false) { FixedSetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings); } /// <summary> /// Alias for SetHoldings to avoid the M-decimal errors. /// </summary> /// <param name="symbol">string symbol we wish to hold</param> /// <param name="percentage">float percentage of holdings desired</param> /// <param name="liquidateExistingHoldings">bool liquidate existing holdings if neccessary to hold this stock</param> /// <param name="tag">Tag the order with a short string.</param> /// <seealso cref="MarketOrder"/> public void FixedSetHoldings(Symbol symbol, float percentage, bool liquidateExistingHoldings = false, string tag = "") { FixedSetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag); } /// <summary> /// Alias for SetHoldings to avoid the M-decimal errors. /// </summary> /// <param name="symbol">string symbol we wish to hold</param> /// <param name="percentage">float percentage of holdings desired</param> /// <param name="liquidateExistingHoldings">bool liquidate existing holdings if neccessary to hold this stock</param> /// <param name="tag">Tag the order with a short string.</param> /// <seealso cref="MarketOrder"/> public void FixedSetHoldings(Symbol symbol, int percentage, bool liquidateExistingHoldings = false, string tag = "") { FixedSetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag); } /// <summary> /// Automatically place an order which will set the holdings to between 100% or -100% of *PORTFOLIO VALUE*. /// E.g. SetHoldings("AAPL", 0.1); SetHoldings("IBM", -0.2); -> Sets portfolio as long 10% APPL and short 20% IBM /// E.g. SetHoldings("AAPL", 2); -> Sets apple to 2x leveraged with all our cash. /// </summary> /// <param name="symbol">Symbol indexer</param> /// <param name="percentage">decimal fraction of portfolio to set stock</param> /// <param name="liquidateExistingHoldings">bool flag to clean all existing holdings before setting new faction.</param> /// <param name="tag">Tag the order with a short string.</param> /// <seealso cref="MarketOrder"/> public void FixedSetHoldings(Symbol symbol, decimal percentage, bool liquidateExistingHoldings = false, string tag = "") { //Initialize Requirements: Security security; if (!Securities.TryGetValue(symbol, out security)) { Error(symbol.ToString() + " not found in portfolio. Request this data when initializing the algorithm."); return; } //If they triggered a liquidate if (liquidateExistingHoldings) { foreach (var kvp in Portfolio) { var holdingSymbol = kvp.Key; var holdings = kvp.Value; if (holdingSymbol != symbol && holdings.AbsoluteQuantity > 0) { //Go through all existing holdings [synchronously], market order the inverse quantity: Order(holdingSymbol, -holdings.Quantity, false, tag); } } } //Only place trade if we've got > 1 share to order. var quantity = FixedCalculateOrderQuantity(symbol, percentage); if (Math.Abs(quantity) > 0) { MarketOrder(symbol, quantity, false, tag); } } private bool TryOrderQuantity(int orderQuantity, Security security, decimal marginRemaining, decimal targetOrderValue) { //note that margin requirements and order value + fees are assumed to be monotonic w.r.t. orderQuantity, //otherwise binary search would not work and an exhaustive search would be necessary var order = new MarketOrder(security.Symbol, orderQuantity, UtcTime); var orderValue = order.GetValue(security); var orderFees = security.FeeModel.GetOrderFee(security, order); // calculate the margin required for the order var marginRequired = security.MarginModel.GetInitialMarginRequiredForOrder(security, order); return marginRequired <= marginRemaining && orderValue + orderFees <= targetOrderValue; } /// <summary> /// Calculate the order quantity to achieve target-percent holdings. /// </summary> /// <param name="symbol">Security object we're asking for</param> /// <param name="target">Target percentag holdings, this is an unlevered value, so /// if you have 2x leverage and request 100% holdings, it will utilize half of the /// available margin</param> /// <returns>Order quantity to achieve this percentage</returns> public int FixedCalculateOrderQuantity(Symbol symbol, decimal target) { var security = Securities[symbol]; return FixedCalculateOrderQuantity(symbol, target, (int)security.Holdings.Quantity); } public int FixedCalculateOrderQuantity(Symbol symbol, decimal target, int initialQuantity) { var security = Securities[symbol]; var price = security.Price; if (price == 0) price = (security.BidPrice + security.AskPrice) / 2; // if targeting zero, simply return the negative of the quantity if (target == 0) return (int)-initialQuantity; // can't order it if we don't have data if (price == 0) return 0; // this is the value in dollars that we want our holdings to have var targetPortfolioValue = target * Portfolio.TotalPortfolioValue; var quantity = initialQuantity; var currentHoldingsValue = price * quantity; // remove directionality, we'll work in the land of absolutes var targetOrderValue = Math.Abs(targetPortfolioValue - currentHoldingsValue); var direction = targetPortfolioValue > currentHoldingsValue ? OrderDirection.Buy : OrderDirection.Sell; // determine the unit price in terms of the account currency var unitPrice = new MarketOrder(symbol, 1, UtcTime).GetValue(security); // calculate the total margin available var marginRemaining = Portfolio.GetMarginRemaining(symbol, direction); if (marginRemaining <= 0) return 0; // compute the initial order quantity int orderQuantity; int maxOrderQuantity = (int)(targetOrderValue / unitPrice); //upper bound int minOrderQuantity = 1; //lower bound if (TryOrderQuantity(maxOrderQuantity, security, marginRemaining, targetOrderValue)) { orderQuantity = maxOrderQuantity; } else if (!TryOrderQuantity(minOrderQuantity, security, marginRemaining, targetOrderValue)) { orderQuantity = 0; } else { //binary search for (;;) { orderQuantity = (maxOrderQuantity + minOrderQuantity) / 2; if (orderQuantity == minOrderQuantity) { orderQuantity = minOrderQuantity; break; } if (TryOrderQuantity(orderQuantity, security, marginRemaining, targetOrderValue)) { minOrderQuantity = orderQuantity; } else { maxOrderQuantity = orderQuantity; } } } //Rounding off Order Quantity to the nearest multiple of Lot Size if (orderQuantity % Convert.ToInt32(security.SymbolProperties.LotSize) != 0) { orderQuantity = orderQuantity - (orderQuantity % Convert.ToInt32(security.SymbolProperties.LotSize)); } // add directionality back in return (direction == OrderDirection.Sell ? -1 : 1) * orderQuantity; } } }
using QuantConnect.Orders.Slippage; using System; using QuantConnect.Orders; using QuantConnect.Securities; namespace QuantConnect.Algorithm.CSharp { class OrderTypeDependentSlippageModel : ISlippageModel { public ISlippageModel LimitOrderSlippage { get; set; } public ISlippageModel MarketOrderSlippage { get; set; } public ISlippageModel MarketOnCloseOrderSlippage { get; set; } public ISlippageModel MarketOnOpenOrderSlippage { get; set; } public ISlippageModel StopLimitOrderSlippage { get; set; } public ISlippageModel StopMarketOrderSlippage { get; set; } public OrderTypeDependentSlippageModel(ISlippageModel defaultModel) { LimitOrderSlippage = defaultModel; MarketOrderSlippage = defaultModel; MarketOnCloseOrderSlippage = defaultModel; MarketOnOpenOrderSlippage = defaultModel; StopLimitOrderSlippage = defaultModel; StopMarketOrderSlippage = defaultModel; } public void SetMarketSlippageModel(ISlippageModel model) { MarketOrderSlippage = model; MarketOnCloseOrderSlippage = model; MarketOnOpenOrderSlippage = model; StopMarketOrderSlippage = model; } public void SetLimitSlippageModel(ISlippageModel model) { LimitOrderSlippage = model; StopLimitOrderSlippage = model; } public decimal GetSlippageApproximation(Security asset, Order order) { switch (order.Type) { case OrderType.Limit: return LimitOrderSlippage.GetSlippageApproximation(asset, order); case OrderType.Market: return MarketOrderSlippage.GetSlippageApproximation(asset, order); case OrderType.MarketOnClose: return MarketOnCloseOrderSlippage.GetSlippageApproximation(asset, order); case OrderType.MarketOnOpen: return MarketOnOpenOrderSlippage.GetSlippageApproximation(asset, order); case OrderType.StopLimit: return StopLimitOrderSlippage.GetSlippageApproximation(asset, order); case OrderType.StopMarket: return StopMarketOrderSlippage.GetSlippageApproximation(asset, order); default: throw new NotImplementedException("Slippage specialization not implemented for order type " + order.Type.ToString()); } } } }
using System; using System.Collections.Generic; using System.Reflection; namespace QuantConnect.Algorithm.CSharp { public static class Xtend { public static FieldInfo GetPrivateField(Type type, string name) { return type.GetField(name, BindingFlags.NonPublic | BindingFlags.Instance); } public static FieldInfo GetPrivateField<MyType>(this MyType dummy, string name) { return GetPrivateField(typeof(MyType), name); } public static object GetPrivateFieldValue(Type type, object instance, string name) { var fieldInfo = GetPrivateField(type, name); if (fieldInfo == null) throw new InvalidOperationException("Unable to find field with name " + name); return fieldInfo.GetValue(instance); } public static object GetPrivateFieldValue<MyType>(this MyType instance, string name) { return GetPrivateFieldValue(typeof(MyType), instance, name); } public static T Clamp<T>(this T val, T min, T max) where T : IComparable { XMath.Clamp(ref val, min, max); return val; } public static void Shuffle<T>(this IList<T> list, Random rng) { int n = list.Count; while (n > 1) { n--; int k = rng.Next(n + 1); T value = list[k]; list[k] = list[n]; list[n] = value; } } public static int Argmax(this IList<int> list) { int maxIndex = list.Count - 1; var max = list[maxIndex]; for (int index = list.Count - 2; index >= 0; --index) { var x = list[index]; if (x > max) { maxIndex = index; max = x; } } return maxIndex; } public static int Argmin(this IList<int> list) { int minIndex = list.Count - 1; var min = list[minIndex]; for (int index = list.Count - 2; index >= 0; --index) { var x = list[index]; if (x < min) { minIndex = index; min = x; } } return minIndex; } public static int Argmax(this IList<double> list) { int maxIndex = list.Count - 1; var max = list[maxIndex]; for (int index = list.Count - 2; index >= 0; --index) { var x = list[index]; if (x > max) { maxIndex = index; max = x; } } return maxIndex; } public static int Argmin(this IList<double> list) { int minIndex = list.Count - 1; var min = list[minIndex]; for (int index = list.Count - 2; index >= 0; --index) { var x = list[index]; if (x < min) { minIndex = index; min = x; } } return minIndex; } } }
using System; using System.Collections.Generic; //found and copied from random site on Internetz namespace QuantConnect.Algorithm.CSharp { public sealed class PriorityQueue<T> where T : IComparable<T> { private readonly List<T> _data = new List<T>(); public PriorityQueue() { _data = new List<T>(); } public void Enqueue(T item) { _data.Add(item); int ci = _data.Count - 1; // child index; start at end while (ci > 0) { int pi = (ci - 1) / 2; // parent index if (_data[ci].CompareTo(_data[pi]) >= 0) break; // child item is larger than (or equal) parent so we're done T tmp = _data[ci]; _data[ci] = _data[pi]; _data[pi] = tmp; ci = pi; } } public T Dequeue() { // assumes pq is not empty; up to calling code int li = _data.Count - 1; // last index (before removal) T frontItem = _data[0]; // fetch the front _data[0] = _data[li]; _data.RemoveAt(li); --li; // last index (after removal) int pi = 0; // parent index. start at front of pq while (true) { int ci = pi * 2 + 1; // left child index of parent if (ci > li) break; // no children so done int rc = ci + 1; // right child if (rc <= li && _data[rc].CompareTo(_data[ci]) < 0) // if there is a rc (ci + 1), and it is smaller than left child, use the rc instead ci = rc; if (_data[pi].CompareTo(_data[ci]) <= 0) break; // parent is smaller than (or equal to) smallest child so done T tmp = _data[pi]; _data[pi] = _data[ci]; _data[ci] = tmp; // swap parent and child pi = ci; } return frontItem; } public T Peek() { T frontItem = _data[0]; return frontItem; } public int Count { get { return _data.Count; } } public override string ToString() { string s = ""; for (int i = 0; i < _data.Count; ++i) s += _data[i].ToString() + " "; s += "count = " + _data.Count; return s; } internal bool IsConsistent() { // is the heap property true for all data? if (_data.Count == 0) return true; int li = _data.Count - 1; // last index for (int pi = 0; pi < _data.Count; ++pi) // each parent index { int lci = 2 * pi + 1; // left child index int rci = 2 * pi + 2; // right child index if (lci <= li && _data[pi].CompareTo(_data[lci]) > 0) return false; // if lc exists and it's greater than parent then bad. if (rci <= li && _data[pi].CompareTo(_data[rci]) > 0) return false; // check the right child too. } return true; // passed all checks } } }
/* * 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 QuantConnect.Indicators; using System; namespace QuantConnect.Algorithm.CSharp { /// <summary> /// This indicator computes the n-period population standard deviation. /// </summary> public class StandardDeviationOverflowSafe : Variance { /// <summary> /// Initializes a new instance of the StandardDeviation class with the specified period. /// /// Evaluates the standard deviation of samples in the lookback period. /// On a dataset of size N will use an N normalizer and would thus be biased if applied to a subset. /// </summary> /// <param name="period">The sample size of the standard deviation</param> public StandardDeviationOverflowSafe(int period) : this("STD" + period, period) { } /// <summary> /// Initializes a new instance of the StandardDeviation class with the specified name and period. /// /// Evaluates the standard deviation of samples in the lookback period. /// On a dataset of size N will use an N normalizer and would thus be biased if applied to a subset. /// </summary> /// <param name="name">The name of this indicator</param> /// <param name="period">The sample size of the standard deviation</param> public StandardDeviationOverflowSafe(string name, int period) : base(name, period) { } /// <summary> /// Gets a flag indicating when this indicator is ready and fully initialized /// </summary> public override bool IsReady { get { return Samples >= Period; } } /// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <param name="window">The window for the input history</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(IReadOnlyWindow<IndicatorDataPoint> window, IndicatorDataPoint input) { double val = Math.Sqrt((double)base.ComputeNextValue(window, input)); return (decimal)val.Clamp(_min, _max); } private static readonly double _max = (double)decimal.MaxValue * 0.99999999; private static readonly double _min = (double)decimal.MinValue * 0.99999999; } }
/* * 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 QuantConnect.Data.Market; using QuantConnect.Securities; using QuantConnect.Orders.Fills; using QuantConnect.Orders; using QuantConnect.Data; using System.Linq; namespace QuantConnect.Algorithm.CSharp { /// <summary> /// Represents the default fill model used to simulate order fills /// but with the following modification for limit orders: /// Trade volumes do not allow a fill unless they are >= VolumeThreshold. /// Limitation: Quotes are not used. /// </summary> public class ImmediateWhenVolumeFillModel : ImmediateFillModel { private readonly QCAlgorithm _algo; public ImmediateWhenVolumeFillModel(QCAlgorithm algo) { _algo = algo; VolumeThreshold = 1; OrderDelay = TimeSpan.FromSeconds(0); } /// <summary> /// Threshold below which orders do not fill. Defaults to 1. /// </summary> public long VolumeThreshold { get; set; } /// <summary> /// Uniform delay to orders in backtest simulation. /// Note, has a different meaning in FillOnNextAvailableTick. /// </summary> public TimeSpan OrderDelay { get; set; } /// <summary> /// Optional tick fill source. /// </summary> public TickFillSource TickFillSource { get; set; } /// <summary> /// For best effort HFT simulation with second precision tick data. /// If this is used, OrderDelay instead works as a barrier beyond which /// last price is used instead. /// </summary> public bool FillOnNextAvailableTick { get; set; } /// <summary> /// Treat asset as if a fill will always be possible at same price as last tick. /// </summary> public bool HighlyLiquidAsset { get; set; } /// <summary> /// Default limit order fill model in the base security class. /// </summary> /// <param name="asset">Security asset we're filling</param> /// <param name="order">Order packet to model</param> /// <returns>Order fill information detailing the average price and quantity filled.</returns> /// <seealso cref="StopMarketFill(Security, StopMarketOrder)"/> /// <seealso cref="MarketFill(Security, MarketOrder)"/> public override OrderEvent LimitFill(Security asset, LimitOrder order) { if (FillOnNextAvailableTick) throw new NotSupportedException("FillOnNextAvailableTick"); //Initialise; var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone); var fill = new OrderEvent(order, utcTime, 0); fill.Status = order.Status; //necessary, engine will process fill if quantity filled != 0 or status differs //If its cancelled don't need anymore checks: if (order.Status == OrderStatus.Canceled) return fill; //Get the range of prices in the last bar: var prices = GetPrices(asset, order); if (prices == null) return fill; if (prices.Volume < VolumeThreshold) return fill; if (prices.Time < order.Time + OrderDelay) return fill; //-> Valid Live/Model Order: switch (order.Direction) { case OrderDirection.Buy: //Buy limit seeks lowest price if (prices.Low < order.LimitPrice) { //Set order fill: fill.Status = OrderStatus.Filled; //TODO: include option to fill "current bar" order was created in with below price, which was default QC code (unfortunately, leads to highly unrealistic fills with waiting limit orders) //fill.FillPrice = Math.Min(prices.High, order.LimitPrice); fill.FillPrice = order.LimitPrice; } break; case OrderDirection.Sell: //Sell limit seeks highest price possible if (prices.High > order.LimitPrice) { fill.Status = OrderStatus.Filled; //TODO: include option to fill "current bar" order was created in with below price, which was default QC code (unfortunately, leads to highly unrealistic fills with waiting limit orders) //fill.FillPrice = Math.Max(prices.Low, order.LimitPrice); fill.FillPrice = order.LimitPrice; } break; } // assume the order completely filled if (fill.Status == OrderStatus.Filled) { fill.FillQuantity = order.Quantity; fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order); } fill.UtcTime = prices.Time; return fill; } /// <summary> /// Default market fill model for the base security class. Fills at the last traded price. /// </summary> /// <param name="asset">Security asset we're filling</param> /// <param name="order">Order packet to model</param> /// <returns>Order fill information detailing the average price and quantity filled.</returns> /// <seealso cref="SecurityTransactionModel.StopMarketFill"/> /// <seealso cref="SecurityTransactionModel.LimitFill"/> public override OrderEvent MarketFill(Security asset, MarketOrder order) { //Default order event to return. var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone); var fill = new OrderEvent(order, utcTime, 0); fill.Status = order.Status; //necessary, engine will process fill if quantity filled != 0 or status differs if (order.Status == OrderStatus.Canceled) return fill; // make sure the exchange is open before filling if (!IsExchangeOpen(asset)) return fill; var prices = GetPrices(asset, order); if (prices == null) return fill; if (!HighlyLiquidAsset && prices.Volume < VolumeThreshold) return fill; var maxTime = prices.Time; if (HighlyLiquidAsset && TickFillSource == null && _algo.UtcTime > maxTime) maxTime = _algo.UtcTime; var orderTime = order.Time; if (!FillOnNextAvailableTick) orderTime += OrderDelay; if (maxTime <= orderTime) return fill; //Order [fill]price for a market order model is the current security price fill.FillPrice = prices.Current; fill.Status = OrderStatus.Filled; //Calculate the model slippage: e.g. 0.01c var slip = asset.SlippageModel.GetSlippageApproximation(asset, order); //Apply slippage switch (order.Direction) { case OrderDirection.Buy: fill.FillPrice += slip; break; case OrderDirection.Sell: fill.FillPrice -= slip; break; } // assume the order completely filled if (fill.Status == OrderStatus.Filled) { fill.FillQuantity = order.Quantity; fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order); } fill.UtcTime = prices.Time; return fill; } /// <summary> /// Get the minimum and maximum price for this security in the last bar: /// </summary> /// <param name="asset">Security asset we're checking</param> /// <param name="direction">The order direction, decides whether to pick bid or ask</param> private Prices GetPrices(Security asset, Order order) { var direction = order.Direction; var low = asset.Low; var high = asset.High; var open = asset.Open; var close = asset.Close; var current = asset.Price; var volume = 0; var time = asset.LocalTime; if (direction == OrderDirection.Hold) { return new Prices(current, open, high, low, close, volume, time, asset.Exchange.TimeZone); } if (TickFillSource != null) { var closestTick = asset.Cache.GetData<Tick>(); var orderTime = order.Time; if (!FillOnNextAvailableTick) orderTime += OrderDelay; foreach (var t in TickFillSource.Ticks) { if (t.TickType != TickType.Trade) continue; if (t.Quantity < VolumeThreshold) continue; var tickTime = t.Time.ConvertToUtc(asset.Exchange.TimeZone); if (tickTime > orderTime) { var fillTime = orderTime; if (FillOnNextAvailableTick) fillTime = tickTime; if (HighlyLiquidAsset && !FillOnNextAvailableTick) { var closestTickTime = closestTick.Time.ConvertToUtc(asset.Exchange.TimeZone); //allow using last price despite being from past if (Math.Abs((tickTime - orderTime).TotalSeconds) < Math.Abs((closestTickTime - orderTime).TotalSeconds)) { closestTick = t; //_algo.Debug("before order: " + (closestTickTime - orderTime).TotalSeconds); } else { //_algo.Debug("before order: " + (closestTickTime - orderTime).TotalSeconds); } if (closestTickTime > fillTime) fillTime = closestTickTime; } else { closestTick = t; } return new Prices(closestTick.Price, open, high, low, close, closestTick.Quantity, fillTime); } else { closestTick = t; } } return null; } var tick = asset.Cache.GetData<Tick>(); if (tick != null) { return new Prices(tick.Price, open, high, low, close, tick.Quantity, tick.Time, asset.Exchange.TimeZone); } var tradeBar = asset.Cache.GetData<TradeBar>(); if (tradeBar != null) { return new Prices(tradeBar, asset.Exchange.TimeZone); } var lastData = asset.GetLastData(); var lastBar = lastData as TradeBar; if (lastBar != null) { return new Prices(lastBar, asset.Exchange.TimeZone); } return new Prices(current, open, high, low, close, volume, time, asset.Exchange.TimeZone); } /// <summary> /// Determines if the exchange is open using the current time of the asset /// </summary> private static bool IsExchangeOpen(Security asset) { if (!asset.Exchange.DateTimeIsOpen(asset.LocalTime)) { // if we're not open at the current time exactly, check the bar size, this handle large sized bars (hours/days) var currentBar = asset.GetLastData(); if (asset.LocalTime.Date != currentBar.EndTime.Date || !asset.Exchange.IsOpenDuringBar(currentBar.Time, currentBar.EndTime, false)) { return false; } } return true; } private class Prices { public readonly decimal Current; public readonly decimal Open; public readonly decimal High; public readonly decimal Low; public readonly decimal Close; public readonly decimal Volume; public readonly DateTime Time; public Prices(TradeBar bar, NodaTime.DateTimeZone timeZone) : this(bar.Close, bar.Open, bar.High, bar.Low, bar.Close, bar.Volume, bar.Time, timeZone) { } public Prices(decimal current, decimal open, decimal high, decimal low, decimal close, decimal volume, DateTime time, NodaTime.DateTimeZone timeZone) { Current = current; Open = open == 0 ? current : open; High = high == 0 ? current : high; Low = low == 0 ? current : low; Close = close == 0 ? current : close; Volume = volume; Time = time.ConvertToUtc(timeZone); } public Prices(decimal current, decimal open, decimal high, decimal low, decimal close, decimal volume, DateTime utcTime) { Current = current; Open = open == 0 ? current : open; High = high == 0 ? current : high; Low = low == 0 ? current : low; Close = close == 0 ? current : close; Volume = volume; Time = utcTime; } } } }
using QuantConnect.Data.Market; using QuantConnect.Orders; using System.Collections.Generic; using System.Linq; namespace QuantConnect.Algorithm.CSharp { public sealed class TickFillSource { private readonly Symbol _symbol; //just to check for validity private List<Tick> _ticksToFill = new List<Tick>(); public IEnumerable<Tick> Ticks { get; private set; } //public int DataVersion { get; private set; } //needed so we can't fill new order with ticks given at same iteration public TickFillSource(Symbol symbol) { _symbol = symbol; } public void SetTicks(IEnumerable<Tick> ticks) { Ticks = ticks.ToArray(); //DataVersion += 1; _ticksToFill.Clear(); //Reverse() because we want to remove newest at tail a lot of the time var range = ticks.Reverse().Where(x => x.TickType == TickType.Trade && x.Symbol == _symbol); //_ticksToFill.AddRange(range); _ticksToFill = range.ToList(); //AddRange having problem with enumerator... } public int GetFirstTickIndex() { return _ticksToFill.Count - 1; } public int GetPreviousTickIndex(int index) { return index + 1; } private Tick PeekOrDequeueTickIfAny(ref int index, bool remove, decimal limit, OrderDirection direction) { //a more accurate model that takes into account volume is most likely not needed //thus this (more) simple and fast implementation while (index >= 0) { var tick = _ticksToFill[index]; bool match = false; if (direction == OrderDirection.Buy) { if (tick.Price < limit) match = true; } else if (direction == OrderDirection.Sell) { if (tick.Price > limit) match = true; } if (remove) _ticksToFill.RemoveAt(index); index -= 1; if (match) return tick; } return null; } public Tick DequeueNextTickIfAny(ref int index, decimal limit, OrderDirection direction) { return PeekOrDequeueTickIfAny(ref index, true, limit, direction); } public Tick PeekNextTickIfAny(ref int index, decimal limit, OrderDirection direction) { return PeekOrDequeueTickIfAny(ref index, false, limit, direction); } } }
// Accord Machine Learning Library // The Accord.NET Framework // http://accord-framework.net // // Copyright © Alex Risman, 2016 // https://github.com/mthmn20 // // Copyright © César Souza, 2009-2017 // cesarsouza at gmail.com // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // namespace QuantConnect.Algorithm.CSharp { using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Runtime.Serialization; using Accord.Math; using System.Threading; using Accord.MachineLearning; using Accord.MachineLearning.DecisionTrees; /// <summary> /// Random Forest. /// </summary> /// /// <remarks> /// <para> /// Represents a random forest of <see cref="DecisionTree"/>s. For /// sample usage and example of learning, please see the documentation /// page for <see cref="RandomForestLearning"/>.</para> /// </remarks> /// /// <example> /// <para> /// This example shows the simplest way to induce a decision tree with continuous variables.</para> /// <code source="Unit Tests\Accord.Tests.MachineLearning\DecisionTrees\RandomForestTest.cs" region="doc_iris" /> /// <para> /// The next example shows how to induce a decision tree with continuous variables using a /// <see cref="Accord.Statistics.Filters.Codification">codebook</see> to manage how input /// variables should be encoded.</para> /// <code source="Unit Tests\Accord.Tests.MachineLearning\DecisionTrees\RandomForestTest.cs" region="doc_nursery" /> /// </example> /// /// <seealso cref="DecisionTree"/> /// <seealso cref="RandomForestLearning"/> /// [Serializable] public class DynamicForest : MulticlassClassifierBase, IParallel { [NonSerialized] private ParallelOptions parallelOptions; /// <summary> /// Gets the trees in the random forest. /// </summary> /// public readonly List<MulticlassClassifierBase<double[]>> Trees = new List<MulticlassClassifierBase<double[]>>(); /// <summary> /// Gets the number of classes that can be recognized /// by this random forest. /// </summary> /// [Obsolete("Please use NumberOfOutputs instead.")] public int Classes { get { return NumberOfOutputs; } } /// <summary> /// Gets or sets the parallelization options for this algorithm. /// </summary> /// public ParallelOptions ParallelOptions { get { return parallelOptions; } set { parallelOptions = value; } } /// <summary> /// Gets or sets a cancellation token that can be used /// to cancel the algorithm while it is running. /// </summary> /// public CancellationToken Token { get { return ParallelOptions.CancellationToken; } set { ParallelOptions.CancellationToken = value; } } /// <summary> /// Creates a new random forest. /// </summary> /// /// <param name="trees">The number of trees in the forest.</param> /// <param name="classes">The number of classes in the classification problem.</param> /// public DynamicForest(int classes) { this.NumberOfOutputs = classes; this.ParallelOptions = new ParallelOptions(); } /// <summary> /// Computes the decision output for a given input vector. /// </summary> /// /// <param name="data">The input vector.</param> /// /// <returns>The forest decision for the given vector.</returns> /// [Obsolete("Please use Decide() instead.")] public int Compute(double[] data) { return Decide(data); } /// <summary> /// Computes a class-label decision for a given <paramref name="input" />. /// </summary> /// <param name="input">The input vector that should be classified into /// one of the <see cref="ITransform.NumberOfOutputs" /> possible classes.</param> /// <returns>A class-label that best described <paramref name="input" /> according /// to this classifier.</returns> public override int Decide(double[] input) { int[] responses = new int[NumberOfOutputs]; Parallel.For(0, Trees.Count, ParallelOptions, i => { int j = Trees[i].Decide(input); Interlocked.Increment(ref responses[j]); }); return responses.ArgMax(); } public int Decide(double[] input, Func<int, double> treeWeightFunc) { double[] responses = new double[NumberOfOutputs]; Parallel.For(0, Trees.Count, ParallelOptions, i => { try { int j = Trees[i].Decide(input); Add(ref responses[j], treeWeightFunc(i)); } catch (Exception) { //quick fix } }); return responses.ArgMax(); } private static double Add(ref double location1, double value) { double newCurrentValue = location1; // non-volatile read, so may be stale while (true) { double currentValue = newCurrentValue; double newValue = currentValue + value; newCurrentValue = Interlocked.CompareExchange(ref location1, newValue, currentValue); if (newCurrentValue == currentValue) return newValue; } } /// <summary> /// Called when the object is being deserialized. /// </summary> /// [OnDeserializing] protected void OnDeserializingMethod(StreamingContext context) { this.parallelOptions = new ParallelOptions(); } } }
using System; using System.Threading; namespace QuantConnect.Algorithm.CSharp { sealed class PollingThread { private readonly Thread _thread; private readonly CancellationTokenSource _cancellation; private readonly Action _action; private readonly bool _startWithWait; public double PollingInterval { get; set; } public PollingThread(bool startWithWait, Action action) { _startWithWait = startWithWait; _action = action; _cancellation = new CancellationTokenSource(); _thread = new Thread(ThreadFunc); } public void Start() { _thread.Start(); } private void ThreadFunc() { var token = _cancellation.Token; if (_startWithWait) Wait(); while (!token.IsCancellationRequested) { _action(); Wait(); } } private void Wait() { var endTime = DateTime.Now + TimeSpan.FromSeconds(PollingInterval); while (DateTime.Now <= endTime) { var timeUntilEnd = endTime - DateTime.Now; Thread.Sleep(Math.Min(100, timeUntilEnd.Milliseconds)); } } public void Cancel() { _cancellation.Cancel(); } public void Join() { _thread.Join(); } } }
using QuantConnect.Interfaces; using QuantConnect.Securities; using System; using System.Linq; using System.Reflection; namespace QuantConnect.Algorithm.CSharp { public static class PrivateAPI { private static IBrokerage _brokerage; public static IBrokerage GetBrokerage(QCAlgorithm algo) { if (_brokerage != null) return _brokerage; var orderProcessor = (IOrderProcessor)GetPrivateFieldValue(algo.Transactions, "_orderProcessor"); if (orderProcessor == null) throw new Exception("Cannot find _orderProcessor in SecurityTransactionManager"); var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var allTypes = assemblies.SelectMany(a => a.GetTypes()); var choices = allTypes.Where(t => t.FullName.EndsWith(".BrokerageTransactionHandler")).ToArray(); if (choices.Length > 1) { throw new Exception("More than one: " + string.Join(" ", choices.Select(x => x.FullName).ToArray())); } var brokerageTransactionHandlerType = choices.Single(); _brokerage = (IBrokerage)GetPrivateFieldValue(brokerageTransactionHandlerType, orderProcessor, "_brokerage"); if (_brokerage == null) throw new Exception("Brokerage cannot be accessed via reflection"); return _brokerage; } private static FieldInfo GetPrivateField(Type type, string name) { return type.GetField(name, BindingFlags.NonPublic | BindingFlags.Instance); } private static FieldInfo GetPrivateField<MyType>(MyType dummy, string name) { return GetPrivateField(typeof(MyType), name); } private static object GetPrivateFieldValue(Type type, object instance, string name) { var fieldInfo = GetPrivateField(type, name); return fieldInfo.GetValue(instance); } private static object GetPrivateFieldValue<MyType>(MyType instance, string name) { return GetPrivateFieldValue(typeof(MyType), instance, name); } } }