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