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