| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 |
namespace QuantConnect
{
/*
* QuantConnect University: Full Basic Template:
*
* The underlying QCAlgorithm class is full of helper methods which enable you to use QuantConnect.
* We have explained some of these here, but the full algorithm can be found at:
* https://github.com/QuantConnect/QCAlgorithm/blob/master/QuantConnect.Algorithm/QCAlgorithm.cs
*/
public class BasicTemplateAlgorithm : QCAlgorithm
{
//Initialize the data and resolution you require for your strategy:
string symbol = "EURUSD";
int quantity = 100000;
List<decimal> xBuffer = new List<decimal>();
List<decimal> yBuffer = new List<decimal>();
List<DateTime> yBufferTime = new List<DateTime>();
DateTime prevTickTime = new DateTime();
private OrderTicket CurrentOrder;
private OrderTicket StopLoss;
private OrderTicket ProfitTarget;
public string regPeriod = "M15";
public int fastRegPeriods = 20;
public int slowRegPeriods = 80;
public decimal noOfStandardDeviations = 2;
//previous states of security and indicators (to be campared with current state)
decimal prevTickAvgPrice = 0m;
decimal prevRegFastL0 = 0m;
decimal prevRegFastU0 = 0m;
//Minimum Slope needed for entries. Emperical for now.
decimal minSlowSlope = .000003m; //.5 adj pip per 15 min candle
decimal minFastSlope = .000003m; //.5 adj pip per 15 min candle
//Minimum and Maximum SD for entries. Emperical for now. Maximum can be increased if algo can be switched off during high vol events.
decimal minFastSD = .0005m; //5 adj pips
decimal maxFastSD = .0030m; //30 adj pips
//time for strategy ()..in hours for now
int strategyStartHour = 5; //30 min after LSE open
int strategyEndHour = 8; //30 min before US open
public override void Initialize()
{
//Start and End Date range for the backtest:
SetStartDate(2016, 4, 10);
SetEndDate(DateTime.Now.Date.AddDays(-1));
//Cash allocation
SetCash(50000);
//Add as many securities as you like. All the data will be passed into the event handler:
AddSecurity(SecurityType.Forex, symbol, Resolution.Second);
//MinuteIdentity = Identity(Symbol, Resolution.Minute);
//MinuteIdentity.Updated += MinuteIdentity_Updated;
}
//Data Event Handler: New data arrives here. "TradeBars" type is a dictionary of strings so you can access it by symbol.
public void OnData(TradeBars data)
{
if (!Portfolio.HoldStock)
{
//get last tick values in a second
decimal lastTickAvgPrice = data[symbol].Close;
//get time of tick data
DateTime lastTickTime = data[symbol].Time;
int tickMinute = lastTickTime.Minute;
int tickSecond = lastTickTime.Second;
if(lastTickTime.Minute % 15 == 0 && lastTickTime.Second == 0)
{
Debug(lastTickTime + " " + lastTickAvgPrice);
}
//Debug("tickMinute: " + tickMinute.ToString());
//Debug("tickSecond: " + tickSecond.ToString());
if(xBuffer.Count == 0)
{
//first tick data
yBuffer.Add(lastTickAvgPrice);
yBufferTime.Add(lastTickTime);
xBuffer.Add(1);
prevTickTime = lastTickTime;
}
//Debug("PrevTickTime: " + prevTickTime.ToString());
//Debug("lastTickTime: " + lastTickTime.ToString());
if(xBuffer.Count < slowRegPeriods)
{
//Create first data points
if(lastTickTime > prevTickTime && ((lastTickTime.Minute % 15) < (prevTickTime.Minute % 15)))
{
// new candle
yBuffer.Add(lastTickAvgPrice);
yBufferTime.Add(lastTickTime);
xBuffer.Add(xBuffer.Count + 1);
//Debug(yBufferTime[yBufferTime.Count - 1] + " " + yBuffer[yBuffer.Count - 1]);
}
else
{
//Update price list for new data within candle
yBuffer.RemoveAt(yBuffer.Count - 1);
yBuffer.Add(lastTickAvgPrice);
yBufferTime.RemoveAt(yBufferTime.Count - 1);
yBufferTime.Add(lastTickTime);
}
}
for(int i=0;i<yBuffer.Count;i++)
{
//Debug(yBufferTime[i] + " " + yBuffer[i] + " ");
}
/*
else
//update price list for new data
{
if((lastTickTime.Minute % 15) < (prevTickTime.Minute % 15) && lastTickTime > prevTickTime)
{
//Debug("tickMinute % 15" + (tickMinute % 15));
//update for new candle
yBuffer.RemoveAt(0);
yBuffer.Add(lastTickAvgPrice);
yBufferTime.RemoveAt(0);
yBufferTime.Add(lastTickTime);
}
else
{
//update closing on existing candle
yBuffer.RemoveAt(yBuffer.Count - 1);
yBuffer.Add(lastTickAvgPrice);
yBufferTime.RemoveAt(yBufferTime.Count - 1);
yBufferTime.Add(lastTickTime);
}
for(int i=0;i<yBuffer.Count;i++)
{
Debug(yBufferTime[i] + " " + yBuffer[i] + " ");
}
//calculate new channels
decimal standardError = 0;
decimal lastRegPrice = 0;
decimal regSlope = 0;
//Slow Channel
//CalculateRegressionChannel(xBuffer,yBuffer,out standardError, out lastRegPrice, out regSlope);
decimal regSlowSlope = regSlope;
//Fast Channel
List<decimal> xBufferFast = xBuffer.GetRange(0,fastRegPeriods);
List<decimal> yBufferFast = yBuffer.GetRange(xBuffer.Count - fastRegPeriods, fastRegPeriods);
//CalculateRegressionChannel(xBufferFast,yBufferFast,out standardError, out lastRegPrice, out regSlope);
decimal regFastSlope = regSlope;
decimal regFastM0 = lastRegPrice;
decimal regFastL0 = lastRegPrice - noOfStandardDeviations * standardError;
decimal regFastU0 = lastRegPrice + noOfStandardDeviations * standardError;
decimal sDFast = standardError;
decimal holdings = Portfolio[symbol].Quantity;
//Debug("holdings: " + holdings.ToString());
//Debug("LineRegFast Lower Channel: " + regFastL0.ToString());
//Debug("Slope Slow: " + regSlowSlope.ToString());
//Debug("Time: " + Time.Date.ToString() + Time.Hour.ToString());
//Debug("Price: " + lastTickAvgPrice.ToString());
// Debug("Standard Deviation: " + sDFast.ToString());
//entry conditions
if(Time.Hour >= strategyStartHour && Time.Hour <= strategyEndHour)
{
if(holdings == 0 && sDFast > minFastSD && sDFast < maxFastSD)
{
if(regSlowSlope > minSlowSlope && regFastSlope > minFastSlope && lastTickAvgPrice < regFastL0 && prevTickAvgPrice > prevRegFastL0)
{
//buy signal
//Debug("holdings: " + holdings.ToString());
//Debug("LineRegFast Lower Channel: " + hRegFastL0.ToString());
//Debug("Slope Slow: " + slopeSlow.ToString());
//Debug("Time: " + Time.Date.ToString() + Time.Hour.ToString());
//Debug("Price: " + close.ToString());
//Debug("Standard Deviation: " + sDFast.ToString());
//Debug("noOfDeviations: " + linRegFast.noOfDeviations.ToString());
//Debug("noOfSamples: " + linRegFast.noOfSamples.ToString());
//Debug("noOfPeriods: " + linRegFast.noOfPeriods.ToString());
//Debug("xBuffer Count: " + linRegFast.xBuffer.Count.ToString());
//Debug("yBuffer Count: " + linRegFast.yBuffer.Count.ToString());
//Debug("xBuffer Last: " + linRegFast.xBuffer[linRegFast.xBuffer.Count - 1].ToString());
//Debug("yBuffer Last: " + linRegFast.yBuffer[linRegFast.xBuffer.Count - 1].ToString());
CurrentOrder = Order(symbol, quantity);
StopLoss = StopMarketOrder(symbol,-quantity, 2 * regFastL0 - regFastM0);
ProfitTarget = LimitOrder(symbol, -quantity, regFastM0);
}
else if(regSlowSlope < -minSlowSlope && regFastSlope < -minFastSlope && lastTickAvgPrice > regFastU0 && prevTickAvgPrice < regFastU0)
{
//sell signal
CurrentOrder = Order(symbol, -quantity);
StopLoss = StopMarketOrder(symbol,quantity,2 * regFastU0 - regFastM0);
ProfitTarget = LimitOrder(symbol, quantity,regFastM0);
}
}
}
prevRegFastL0 = regFastL0;
prevRegFastU0 = regFastU0;
}*/
//previous state = present state
prevTickAvgPrice = lastTickAvgPrice;
prevTickTime = lastTickTime;
}
}
// If the StopLoss or ProfitTarget is filled, cancel the other
// If you don't do this, then the ProfitTarget or StopLoss order will remain outstanding
// indefinitely, which will cause very bad behaviors in your algorithm
public override void OnOrderEvent(OrderEvent orderEvent)
{
// Ignore OrderEvents that are not closed
if (!orderEvent.Status.IsClosed())
{
return;
}
// Defensive check
if (ProfitTarget == null || StopLoss == null)
{
return;
}
var filledOrderId = orderEvent.OrderId;
// If the ProfitTarget order was filled, close the StopLoss order
if (ProfitTarget.OrderId == filledOrderId)
{
StopLoss.Cancel();
}
// If the StopLoss order was filled, close the ProfitTarget
if (StopLoss.OrderId == filledOrderId)
{
ProfitTarget.Cancel();
}
}
public void CalculateRegressionChannel(List<decimal> xBuffer, List<decimal> yBuffer, out decimal standardError, out decimal lastRegPrice, out decimal regSlope)
{
int count = xBuffer.Count;
decimal xAvg = xBuffer.Average();
decimal yAvg = yBuffer.Average();
//Debug("xAvg: " + xAvg.ToString());
//Debug("yAvg: " + yAvg.ToString());
List<decimal> regLine = new List<decimal>();
decimal xSD = (decimal)Math.Sqrt(xBuffer.Sum(v => Math.Pow((double)(v - xAvg),2))/(count - 1));
decimal coVariance = 0;
for(int i = 0; i < count; i++)
{
coVariance += xBuffer[i] * yBuffer[i];
}
coVariance = coVariance - count * xAvg * yAvg;
coVariance = coVariance / count;
decimal slope = coVariance / (decimal) Math.Pow((double) xSD,2);
decimal intercept = yAvg - slope * xAvg;
standardError = 0;
lastRegPrice = 0;
regSlope = 0;
for(int i = 0; i < count; i ++)
{
regLine.Add(slope * xBuffer[i] + intercept);
standardError += (decimal) Math.Pow((double) (yBuffer[i] - regLine[i]),2);
}
standardError = (decimal) Math.Sqrt((double) standardError/(count - 1));
lastRegPrice = regLine[regLine.Count - 1];
regSlope = regLine[regLine.Count - 1] - regLine[regLine.Count - 2];
for(int i = 0;i<count;i++)
{
//Debug(" " + yBuffer[i].ToString());
}
//Debug("regLine[last]: " + regLine[regLine.Count - 1]);
//Debug("slope: " + slope.ToString());
//Debug("intercept: " + intercept.ToString());
//Debug("x count: " + count.ToString());
//Debug("y count: " + yBuffer.Count.ToString());
//Debug("Standard Error: " + standardError.ToString());
}
}
}