| Overall Statistics |
|
Total Trades 329 Average Win 4.60% Average Loss -31.09% Compounding Annual Return 70.905% Drawdown 83.300% Expectancy 0.134 Net Profit 59371.866% Sharpe Ratio 1.17 Probabilistic Sharpe Ratio 21.488% Loss Rate 1% Win Rate 99% Profit-Loss Ratio 0.15 Alpha 0.478 Beta 4.615 Annual Standard Deviation 0.785 Annual Variance 0.617 Information Ratio 1.215 Tracking Error 0.677 Treynor Ratio 0.199 Total Fees $0.00 Estimated Strategy Capacity $130000.00 Lowest Capacity Asset SPX500USD 8I |
using System.Linq;
using System.Collections.Generic;
using MathNet.Numerics.Statistics;
namespace QuantConnect.CSharp.Algorithms
{
public class ScalpingAlgorithm : QCAlgorithm
{
private SimpleMovingAverage ema;
private SimpleMovingAverage fma;
//private RateOfChange roc;
private RateOfChange rocvix;
private string symbol = "SPX500USD";
private Delay delayrocvix;
decimal lastPrice;
decimal lastQuantity=0m;
decimal tppp; //$ delta for taking profit based on KDE
DateTime vixtime;
decimal maxProfit;
MyRollingWindow<double> ws;
Symbol _vix;
decimal vix;
decimal currentKDE;
const double sigma = 0.03d;
bool printt = false;
public override void Initialize()
{
SetStartDate(2010, 1, 1);
//SetEndDate(2010, 6, 1);
//SetEndDate(DateTime.Now);
SetCash(10000);
AddSecurity(SecurityType.Cfd, symbol, Resolution.Minute, Market.Oanda, false, 100m, true);
_vix = AddData<Fred>(Fred.CBOE.VIX).Symbol;
SetBenchmark(symbol);
fma = new SimpleMovingAverage(9);
ema = new SimpleMovingAverage(20);
ws = new MyRollingWindow<double>(4*60);
rocvix = new RateOfChange(Int32.Parse(GetParameter("rocvix")));
delayrocvix = new Delay(1).Of(rocvix);
RegisterIndicator(symbol,fma,Resolution.Daily);
RegisterIndicator(symbol,ema,Resolution.Daily);//, data => data.Value);
SetWarmup(60*100);
tppp=decimal.Parse(GetParameter("tppp"));
foreach(var b in History<QuoteBar>(symbol, 201, Resolution.Daily).ToList())
{
fma.Update(new IndicatorDataPoint(b.Time, b.Close));
ema.Update(new IndicatorDataPoint(b.Time, b.Close));
}
foreach(var b in History<QuantConnect.DataSource.Fred>(_vix, 21, Resolution.Daily).ToList())
{
rocvix.Update(new IndicatorDataPoint(b.Time, b.Value));
vix = b.Value;
vixtime=b.Time;
}
foreach(var b in History<QuoteBar>(symbol, 4*60+1, Resolution.Minute).ToList())
{
lastPrice=b.Price;
ws.Add((double)lastPrice);//-llastPrice));
}
Log("vix "+vix);
Log("vixtime "+vixtime);
Log("rocvix "+rocvix.Current.Value);
Log("rocvix-delay "+delayrocvix.Current.Value);
Log("fma" + fma);
Log("ema" + ema);
//SetBrokerageModel(new MyBrokerageModel(AccountType.Margin)/*BrokerageName.OandaBrokerage, AccountType.Margin*/);
SetBrokerageModel(BrokerageName.OandaBrokerage, AccountType.Margin);
}
public override void OnData(Slice data)
{
if(data.ContainsKey(_vix))
{
vix=data[_vix].Value;
vixtime=data[_vix].Time;
rocvix.Update(new IndicatorDataPoint(data[_vix].Time, vix));
if(IsWarmingUp) return;
Log("vix "+vix);
Log("vixtime "+vixtime);
}
}
public void OnData(QuoteBars data)
{
if(IsWarmingUp) return;
if(!data.ContainsKey(symbol)) return;
lastPrice=data[symbol].Price;
ws.Add((double)lastPrice);
if (!ws.IsReady) return;
if(!printt)
{
Log("vix "+vix);
Log("vixtime "+vixtime);
printt=true;
Log("I'm ready ");
}
if ( IsMarketOpen(symbol) )
{
if ( Portfolio[symbol].Invested && lastQuantity>0 )
{
var profitPercent = Securities[symbol].Holdings.UnrealizedProfitPercent;
maxProfit = Math.Max(profitPercent,maxProfit);
if (lastPrice>currentKDE && profitPercent < maxProfit*decimal.Parse(GetParameter("tl")) && maxProfit>decimal.Parse(GetParameter("tp")) )
{
MarketOrder(symbol,-lastQuantity);
lastQuantity=0;
maxProfit=0;
}
else if( highvolatity() )
{
//STOP loss, market is changing direction
MarketOrder(symbol,-lastQuantity);
lastQuantity=0;
maxProfit=0;
}
}
if ( fma>ema && lastQuantity==0)
{
// if trending up
if(!highvolatity())
{
// if volatility is high
int quantity = maxquantity();
currentKDE=getKDE();
if(data[symbol].Bid.Close<currentKDE-1.0m)
{
MarketOrder(symbol,quantity);
lastQuantity=lastQuantity+quantity;
}
}
}
}
}
private bool highvolatity()
{
return (delayrocvix.Current.Value > decimal.Parse(GetParameter("rocstop")) && delayrocvix.Current.Value<rocvix.Current.Value);
}
private int maxquantity()
{
var totalPortfolioValue = Portfolio.TotalPortfolioValue;
var margin = Portfolio.GetMarginRemaining(totalPortfolioValue);
var freemargin = margin / 2;
var marginperunit = (lastPrice*0.05m); //margin utilized per unit
var unitsavailable = margin/marginperunit; //margin utilized per unit
var maxquantity = Math.Round(unitsavailable*0.2m);
return (int)maxquantity;
}
private decimal getKDE()
{
double[,] k = KernelDensityEstimation(ws.ToArray(),sigma,ws.ToArray().Length);
var m = 0d;
var pp=0m;
for (var ii=0; ii<k.Length/2-1; ii++)
{
if(k[ii,1]>m)
{
m = k[ii,1];
pp=(decimal)k[ii,0];
}
}
return pp;
}
public double[,] KernelDensityEstimation(double[] data, double sigma, int nsteps)
{
// probability density function (PDF) signal analysis
// Works like ksdensity in mathlab.
// KDE performs kernel density estimation (KDE)on one - dimensional data
// http://en.wikipedia.org/wiki/Kernel_density_estimation
// Input: -data: input data, one-dimensional
// -sigma: bandwidth(sometimes called "h")
// -nsteps: optional number of abscis points.If nsteps is an
// array, the abscis points will be taken directly from it. (default 100)
// Output: -x: equispaced abscis points
// -y: estimates of p(x)
// This function is part of the Kernel Methods Toolbox(KMBOX) for MATLAB.
// http://sourceforge.net/p/kmbox
// Converted to C# code by ksandric
double[,] result = new double[nsteps, 2];
double[] x = new double[nsteps], y = new double[nsteps];
double MAX = Double.MinValue, MIN = Double.MaxValue;
int N = data.Length; // number of data points
// Find MIN MAX values in data
for (int i = 0; i < N; i++)
{
if (MAX < data[i])
{
MAX = data[i];
}
if (MIN > data[i])
{
MIN = data[i];
}
}
// Like MATLAB linspace(MIN, MAX, nsteps);
x[0] = MIN;
for (int i = 1; i < nsteps; i++)
{
x[i] = x[i - 1] + ((MAX - MIN) / nsteps);
}
// kernel density estimation
double c = 1.0 / (Math.Sqrt(2 * Math.PI * sigma * sigma));
for (int i = 0; i < N; i++)
{
for (int j = 0; j < nsteps; j++)
{
y[j] = y[j] + 1.0 / N * c * Math.Exp(-(data[i] - x[j]) * (data[i] - x[j]) / (2 * sigma * sigma));
}
}
// compilation of the X,Y to result. Good for creating plot(x, y)
for (int i = 0; i < nsteps; i++)
{
result[i, 0] = x[i];
result[i, 1] = y[i];
}
return result;
}
}
}/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using static QuantConnect.StringExtensions;
namespace QuantConnect.Indicators
{
/// <summary>
/// This is a window that allows for list access semantics,
/// where this[0] refers to the most recent item in the
/// window and this[Count-1] refers to the last item in the window
/// </summary>
/// <typeparam name="T">The type of data in the window</typeparam>
public class MyRollingWindow<T> : IReadOnlyWindow<T>
{
// the backing list object used to hold the data
private readonly List<T> _list;
// read-write lock used for controlling access to the underlying list data structure
private readonly ReaderWriterLockSlim _listLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
// the most recently removed item from the window (fell off the back)
private T _mostRecentlyRemoved;
// the total number of samples taken by this indicator
private decimal _samples;
// used to locate the last item in the window as an indexer into the _list
private int _tail;
/// <summary>
/// Initializes a new instance of the RollwingWindow class with the specified window size.
/// </summary>
/// <param name="size">The number of items to hold in the window</param>
public MyRollingWindow(int size)
{
if (size < 1)
{
throw new ArgumentException("RollingWindow must have size of at least 1.", nameof(size));
}
_list = new List<T>(size);
Size = size;
}
/// <summary>
/// Gets the size of this window
/// </summary>
public int Size { get; }
/// <summary>
/// Gets the current number of elements in this window
/// </summary>
public int Count
{
get
{
try
{
_listLock.EnterReadLock();
return _list.Count;
}
finally
{
_listLock.ExitReadLock();
}
}
}
/// <summary>
/// Gets the number of samples that have been added to this window over its lifetime
/// </summary>
public decimal Samples
{
get
{
try
{
_listLock.EnterReadLock();
return _samples;
}
finally
{
_listLock.ExitReadLock();
}
}
}
/// <summary>
/// Gets the most recently removed item from the window. This is the
/// piece of data that just 'fell off' as a result of the most recent
/// add. If no items have been removed, this will throw an exception.
/// </summary>
public T MostRecentlyRemoved
{
get
{
try
{
_listLock.EnterReadLock();
if (Samples <= Size)
{
throw new InvalidOperationException("No items have been removed yet!");
}
return _mostRecentlyRemoved;
}
finally
{
_listLock.ExitReadLock();
}
}
}
/// <summary>
/// Indexes into this window, where index 0 is the most recently
/// entered value
/// </summary>
/// <param name="i">the index, i</param>
/// <returns>the ith most recent entry</returns>
public T[] ToArray()
{
return _list.ToArray();
}
/// <summary>
/// Indexes into this window, where index 0 is the most recently
/// entered value
/// </summary>
/// <param name="i">the index, i</param>
/// <returns>the ith most recent entry</returns>
public T this [int i]
{
get
{
try
{
_listLock.EnterReadLock();
if (Count == 0)
{
throw new ArgumentOutOfRangeException(nameof(i), "Rolling window is empty");
}
else if (i > Size - 1 || i < 0)
{
throw new ArgumentOutOfRangeException(nameof(i), i,
Invariant($"Index must be between 0 and {Size - 1} (rolling window is of size {Size})")
);
}
else if (i > Count - 1)
{
throw new ArgumentOutOfRangeException(nameof(i), i,
Invariant($"Index must be between 0 and {Count - 1} (entry {i} does not exist yet)")
);
}
return _list[(Count + _tail - i - 1) % Count];
}
finally
{
_listLock.ExitReadLock();
}
}
set
{
try
{
_listLock.EnterWriteLock();
if (i < 0 || i > Count - 1)
{
throw new ArgumentOutOfRangeException(nameof(i), i, Invariant($"Must be between 0 and {Count - 1}"));
}
_list[(Count + _tail - i - 1) % Count] = value;
}
finally
{
_listLock.ExitWriteLock();
}
}
}
/// <summary>
/// Gets a value indicating whether or not this window is ready, i.e,
/// it has been filled to its capacity
/// </summary>
public bool IsReady
{
get
{
try
{
_listLock.EnterReadLock();
return Samples >= Size;
}
finally
{
_listLock.ExitReadLock();
}
}
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>1</filterpriority>
public IEnumerator<T> GetEnumerator()
{
// we make a copy on purpose so the enumerator isn't tied
// to a mutable object, well it is still mutable but out of scope
var temp = new List<T>(Count);
try
{
_listLock.EnterReadLock();
for (int i = 0; i < Count; i++)
{
temp.Add(this[i]);
}
return temp.GetEnumerator();
}
finally
{
_listLock.ExitReadLock();
}
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>2</filterpriority>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Adds an item to this window and shifts all other elements
/// </summary>
/// <param name="item">The item to be added</param>
public void Add(T item)
{
try
{
_listLock.EnterWriteLock();
_samples++;
if (Size == Count)
{
// keep track of what's the last element
// so we can reindex on this[ int ]
_mostRecentlyRemoved = _list[_tail];
_list[_tail] = item;
_tail = (_tail + 1) % Size;
}
else
{
_list.Add(item);
}
}
finally
{
_listLock.ExitWriteLock();
}
}
/// <summary>
/// Clears this window of all data
/// </summary>
public void Reset()
{
try
{
_listLock.EnterWriteLock();
_samples = 0;
_list.Clear();
_tail = 0;
}
finally
{
_listLock.ExitWriteLock();
}
}
}
}