| Overall Statistics |
|
Total Trades 172 Average Win 0.74% Average Loss -1.88% Annual Return 0.324% Drawdown 36.200% Expectancy 0.046 Net Profit 6.647% Sharpe Ratio 0.1 Loss Rate 25% Win Rate 75% Profit-Loss Ratio 0.39 Trade Frequency Weekly trades |
using System;
using System.Collections;
using System.Collections.Generic;
namespace QuantConnect
{
using QuantConnect.Securities;
using QuantConnect.Models;
public partial class BasicTemplateAlgorithm : QCAlgorithm, IAlgorithm
{
string symbol = "MSFT";
bool initialized = false;
int numTrackers = 37;
decimal[] movingAverages;
decimal[] multipliers;
bool[,] direction;
LinkedList<GainTracker>[,] gainTrackers;
decimal[,] crossPrice;
int[,] crossCount;
int[,] barsSinceCross;
int bestI = -1;
int bestJ = -1;
//int buySize = 100;
int slowEMAOffset = 3;
int buySize = 500;
int minHistoryLength = 60 * 8 * 20;
//int maxHistoryLength = 60 * 8 * 120;
long time = 0;
bool allowShorting = false;
int stage = 0;
//Initialize the data and resolution you require for your strategy:
public override void Initialize()
{
//Initialize the start, end dates for simulation; cash and data required.
SetStartDate(2000, 01, 01);
SetEndDate(DateTime.Now.Date.AddDays(-1));
SetCash(30000); //Starting Cash in USD.
AddSecurity(SecurityType.Equity, symbol, Resolution.Minute); //Minute, Second or Tick
SetRunMode(RunMode.Series); //Series or Parallel for intraday strategies.
movingAverages = new decimal[numTrackers];
multipliers = new decimal[numTrackers];
direction = new bool[numTrackers, numTrackers];
crossPrice = new decimal[numTrackers, numTrackers];
crossCount = new int[numTrackers, numTrackers];
barsSinceCross = new int[numTrackers, numTrackers];
gainTrackers = new LinkedList<GainTracker>[numTrackers, numTrackers];
decimal multiplier = 1;
for (int i = 0; i < numTrackers; i++) {
multiplier *= .7m;
multipliers[i] = multiplier;
}
}
//Handle TradeBar Events: a TradeBar occurs on a time-interval (second or minute bars)
public override void OnTradeBar(Dictionary<string, TradeBar> data)
{
decimal lastPrice = data[symbol].Close;
decimal fee = Securities[symbol].Model.GetOrderFee(buySize, lastPrice) * 2;
time++;
if (initialized) {
for (int i = 0; i < numTrackers; i++) {
movingAverages[i] += (lastPrice - movingAverages[i]) * multipliers[i];
}
for (int i = 0; i < numTrackers; i++) {
for (int j = i + slowEMAOffset; j < numTrackers; j++) {
bool newDirection = movingAverages[i] > movingAverages[j];
if (direction[i, j] != newDirection) {
decimal diff = (lastPrice - crossPrice[i, j]) * buySize;
if (newDirection) {
gainTrackers[i, j].AddLast(new GainTracker(-diff - fee, barsSinceCross[i, j]));
} else {
gainTrackers[i, j].AddLast(new GainTracker(diff - fee, barsSinceCross[i, j]));
}
if (i == bestI && j == bestJ) {
Debug(bestI + ", " + bestJ);
Debug("Fee: " + fee);
if (allowShorting) {
if (stage == 0) {
if (newDirection) {
stage = 1;
Order(symbol, buySize);
} else {
stage = 2;
Order(symbol, -buySize);
}
} else {
if (newDirection && stage == 2) {
stage = 1;
Order(symbol, 2 * buySize);
} else if (!newDirection && stage == 1) {
stage = 2;
Order(symbol, -2 * buySize);
}
}
} else {
if (newDirection) {
if (Portfolio.HoldStock) {
Order(symbol, -buySize);
}
} else {
if (!Portfolio.HoldStock) {
Order(symbol, buySize);
}
}
}
}
direction[i, j] = newDirection;
crossPrice[i, j] = lastPrice;
crossCount[i, j]++;
barsSinceCross[i, j] = 1;
} else {
barsSinceCross[i, j]++;
}
}
}
if ((allowShorting || !Portfolio.HoldStock) && time > 9600) {
decimal maxGain = .06m;
bestI = -1;
bestJ = -1;
for (int i = 0; i < numTrackers; i++) {
for (int j = i + slowEMAOffset; j < numTrackers; j++) {
if (gainTrackers[i, j].Count > 0) {
int totalDuration = 0;
decimal profits = 0;
foreach (GainTracker g in gainTrackers[i, j]) {
profits += g.profit;
totalDuration += g.time;
}
decimal gainRate = profits / (decimal)totalDuration;
if (gainRate > maxGain && totalDuration > minHistoryLength) {
maxGain = gainRate;
bestI = i;
bestJ = j;
}
if (gainTrackers[i, j].Count > 30) {
gainTrackers[i, j].RemoveFirst();
}
}
}
}
Debug("Max Gain: " + maxGain);
}
} else {
for (int i = 0; i < numTrackers; i++) {
movingAverages[i] = lastPrice;
}
for (int i = 0; i < numTrackers; i++) {
for (int j = i + slowEMAOffset; j < numTrackers; j++) {
direction[i, j] = movingAverages[i] > movingAverages[j];
crossPrice[i, j] = lastPrice;
barsSinceCross[i, j] = 1;
gainTrackers[i, j] = new LinkedList<GainTracker>();
}
}
initialized = true;
}
}
}
public class GainTracker {
public decimal profit;
public int time;
public GainTracker(decimal profit, int time) {
this.profit = profit;
this.time = time;
}
}
}