| Overall Statistics |
|
Total Trades 18 Average Win 1.45% Average Loss -0.70% Compounding Annual Return 0.059% Drawdown 6.700% Expectancy 0.027 Net Profit 0.104% Sharpe Ratio 0.043 Loss Rate 67% Win Rate 33% Profit-Loss Ratio 2.08 Alpha 0.003 Beta -0.002 Annual Standard Deviation 0.07 Annual Variance 0.005 Information Ratio -0.214 Tracking Error 0.15 Treynor Ratio -1.939 Total Fees $18.00 |
-no value-
using Accord.Statistics.Models.Markov;
using Accord.Statistics.Models.Markov.Learning;
namespace QuantConnect
{
/*
* QuantConnect University: 50-10 EMA - Exponential Moving Average Cross
*
* The classic exponential moving average cross implementation using a custom class.
* The algorithm uses allows for a safety margin so you can reduce the "bounciness"
* of the trading to confirm the crossing.
*/
public enum TRADETYPE
{
LOSING,
NEUTRAL,
WINNING
};
public class EMATest : QCAlgorithm
{
//Define required variables:
int quantity = 0;
decimal price = 0;
decimal tolerance = 0m; //0.1% safety margin in prices to avoid bouncing.
string symbol = "SPY";
DateTime sampledToday = DateTime.Now;
List<decimal> _tradeReturns = new List<decimal>();
private const int MAXRETURNS = 4;
//Set up the EMA Class:
ExponentialMovingAverage emaShort;
ExponentialMovingAverage emaLong;
//Initialize the data and resolution you require for your strategy:
public override void Initialize()
{
SetStartDate(2014, 01, 01);
SetEndDate(DateTime.Now);
SetCash(25000);
AddSecurity(SecurityType.Equity, symbol, Resolution.Daily);
emaShort = EMA(symbol, 10, Resolution.Daily);
emaLong = EMA(symbol, 50, Resolution.Daily);
for (int i = 0; i < MAXRETURNS; i++) {
_tradeReturns.Add(0);
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (orderEvent.Status == OrderStatus.Filled && orderEvent.FillQuantity < 0)
{
SecurityHolding s = Securities [orderEvent.Symbol].Holdings;
var profit_pct = s.LastTradeProfit / Portfolio.TotalPortfolioValue;
_tradeReturns.Add (profit_pct);
if (_tradeReturns.Count > MAXRETURNS)
_tradeReturns.RemoveAt (0);
}
}
//Handle TradeBar Events: a TradeBar occurs on every time-interval
public void OnData(TradeBars data) {
//One data point per day:
if (sampledToday.Date == data[symbol].Time.Date) return;
//Only take one data point per day (opening price)
price = Securities[symbol].Close;
sampledToday = data[symbol].Time;
//Wait until EMA's are ready:
if (!emaShort.IsReady || !emaLong.IsReady) return;
//Get fresh cash balance: Set purchase quantity to equivalent 10% of portfolio.
decimal cash = Portfolio.Cash;
int holdings = Portfolio[symbol].Quantity;
//quantity = Convert.ToInt32((cash * 0.5m) / price);
if (holdings > 0) {
//If we're long, or flat: check if EMA crossed negative: and crossed outside our safety margin:
if ((emaShort * (1+tolerance)) < emaLong)
{
//Now go short: Short-EMA signals a negative turn: reverse holdings
Order(symbol, -(holdings));
Log(Time.ToShortDateString() + " > Go Short > Holdings: " + holdings.ToString() + " Quantity:" + quantity.ToString() + " Samples: " + emaShort.Samples);
}
} else if (holdings == 0) {
//If we're short, or flat: check if EMA crossed positive: and crossed outside our safety margin:
if ((emaShort * (1 - tolerance)) > emaLong)
{
//Now go long: Short-EMA crossed above long-EMA by sufficient margin
var quantity = GetNumSymbols(price);
Order(symbol, Math.Abs(holdings) + quantity);
Log(Time.ToShortDateString() + "> Go Long > Holdings: " + holdings.ToString() + " Quantity:" + quantity.ToString() + " Samples: " + emaShort.Samples);
}
}
}
private TRADETYPE PredictNextTrade()
{
var res = TRADETYPE.WINNING;
if (_tradeReturns.Count == 4) {
HiddenMarkovModel hmm = new HiddenMarkovModel(states: 3, symbols: 3);
int[] observationSequence = GetSequence (_tradeReturns);
BaumWelchLearning teacher = new BaumWelchLearning(hmm);
// and call its Run method to start learning
double error = teacher.Run(observationSequence);
int[] predict = hmm.Predict (observationSequence, 1);
if (predict [0] == 0) {
res = TRADETYPE.LOSING;
} else if (predict [0] == 1) {
res = TRADETYPE.NEUTRAL;
} else if (predict [0] == 2) {
res = TRADETYPE.WINNING;
}
}
return res;
}
private int[] GetSequence(List<decimal> returns)
{
int[] observationSequence = new int[4];
for(int i=0;i<returns.Count;i++)
{
if (returns [i] < 0m)
observationSequence [i] = 0; // loss
else if (returns [i] > 0m && returns [i] < 0.01m)
observationSequence [i] = 1; //neutral, small win
else
observationSequence [i] = 2; //big win
};
return observationSequence;
}
private int GetNumSymbols(decimal currentPrice)
{
var direction = PredictNextTrade ();
var predict_risk = 1.0m;
switch (direction) {
case TRADETYPE.LOSING:
predict_risk = 0.5m;
break;
case TRADETYPE.NEUTRAL:
predict_risk = 0.8m;
break;
}
var quantity = (int)(Math.Round (predict_risk* Portfolio.Cash/currentPrice));
return quantity;
}
}
}