Overall Statistics |
Total Trades 685 Average Win 2.25% Average Loss -0.81% Compounding Annual Return 53.261% Drawdown 14.800% Expectancy 0.331 Net Profit 135.222% Sharpe Ratio 1.715 Loss Rate 65% Win Rate 35% Profit-Loss Ratio 2.76 Alpha 0.349 Beta 0.149 Annual Standard Deviation 0.217 Annual Variance 0.047 Information Ratio 0.923 Tracking Error 0.235 Treynor Ratio 2.494 Total Fees $910.76 |
using QuantConnect.Data.Consolidators; namespace QuantConnect { /* * John Ehlers' MAMA and FAMA * (programmed by Jean-Paul van Brakel) */ public class BasicTemplateAlgorithm : QCAlgorithm { public string _ticker = "AAPL"; // which stock ticker public static int _consolidated_minutes = 10; // number of minutes public static double MAMA_FastLimit = 0.10; // fast parameter public static double MAMA_SlowLimit = 0.001; // slow parameter private TradeBarConsolidator consolidator; private readonly RollingWindow<double> Prices = new RollingWindow<double>(9); private readonly RollingWindow<double> Smooths = new RollingWindow<double>(9); private readonly RollingWindow<double> Periods = new RollingWindow<double>(9); private readonly RollingWindow<double> Detrenders = new RollingWindow<double>(9); private readonly RollingWindow<double> Q1s = new RollingWindow<double>(9); private readonly RollingWindow<double> I1s = new RollingWindow<double>(9); private readonly RollingWindow<double> Q2s = new RollingWindow<double>(9); private readonly RollingWindow<double> I2s = new RollingWindow<double>(9); private readonly RollingWindow<double> Res = new RollingWindow<double>(9); private readonly RollingWindow<double> Ims = new RollingWindow<double>(9); private readonly RollingWindow<double> SmoothPeriods= new RollingWindow<double>(9); private readonly RollingWindow<double> Phases = new RollingWindow<double>(9); private readonly RollingWindow<double> MAMAs = new RollingWindow<double>(9); private readonly RollingWindow<double> FAMAs = new RollingWindow<double>(9); private Chart plotter; decimal _oldprice = 100000; decimal _price; int _old_dir = 0; int _mama_dir = 0; int _trend_dir = 0; public override void Initialize() { //Start and End Date range for the backtest: SetStartDate(2012, 1, 1); SetEndDate(2014, 1, 1); SetCash(10000); AddSecurity(SecurityType.Equity, _ticker, Resolution.Minute); consolidator = new TradeBarConsolidator(TimeSpan.FromMinutes(_consolidated_minutes)); consolidator.DataConsolidated += ConsolidatedHandler; SubscriptionManager.AddConsolidator(_ticker, consolidator); plotter = new Chart("MAMA", ChartType.Overlay); plotter.AddSeries(new Series("Price", SeriesType.Line)); plotter.AddSeries(new Series("MAMA", SeriesType.Line)); plotter.AddSeries(new Series("FAMA", SeriesType.Line)); AddChart(plotter); //Warm up the variables for (int i = 0; i < 7; i++) { Periods.Add(0.0); Smooths.Add(0.0); Detrenders.Add(0.0); Q1s.Add(0.0); I1s.Add(0.0); Q2s.Add(0.0); I2s.Add(0.0); Res.Add(0.0); Ims.Add(0.0); SmoothPeriods.Add(0.0); Phases.Add(0.0); MAMAs.Add(0.0); FAMAs.Add(0.0); } } public void OnData(TradeBars data) { // ignore this for now } public void ConsolidatedHandler(object sender, TradeBar data) { Prices.Add((double)(data.High + data.Low)/2); _price = data.Close; if (!Prices.IsReady) return; // MAMA and FAMA // ********************************************************************************************************* double Smooth = (double) ((4*Prices[0] + 3*Prices[1] + 2*Prices[2] + Prices[3])/10); Smooths.Add(Smooth); double Detrender = (.0962*Smooths[0] + .5769*Smooths[2] - .5769*Smooths[4] - .0962*Smooths[6])*(.075*Periods[1] + .54); Detrenders.Add(Detrender); // Compute InPhase and Quadrature components Q1s.Add((.0962*Detrenders[0] + .5769*Detrenders[2] - .5769*Detrenders[4] - .0962*Detrenders[6])*(.075*Periods[1] + .54)); I1s.Add(Detrenders[3]); // Advance the phase of I1 and Q1 by 90 degrees double jI = (.0962*I1s[0] + .5769*I1s[2] - .5769*I1s[4] - .0962*I1s[6])*(.075*Periods[1] + .54); double jQ = (.0962*Q1s[0] + .5769*Q1s[2] - .5769*Q1s[4] - .0962*Q1s[6])*(.075*Periods[1] + .54); // Phasor addition for 3 bar averaging double I2 = I1s[0] - jQ; double Q2 = Q1s[0] + jI; // Smooth the I and Q components before applying the discriminator I2s.Add(.2*I2 + .8*I2s[0]); Q2s.Add(.2*Q2 + .8*Q2s[0]); // Homodyne Discriminator double Re = I2s[0]*I2s[1] + Q2s[0]*Q2s[1]; double Im = I2s[0]*Q2s[1] - Q2s[0]*I2s[1]; Res.Add(.2*Re + .8*Res[0]); Ims.Add(.2*Im + .8*Ims[0]); double Period = 0; if (Im != 0 && Re != 0) Period = (2*Math.PI)/Math.Atan(Im/Re); if (Period > 1.5*Periods[0]) Period = 1.5*Periods[0]; if (Period < .67*Periods[0]) Period = .67*Periods[0]; if (Period < 6) Period = 6; if (Period > 50) Period = 50; Periods.Add(.2*Period + .8*Periods[0]); SmoothPeriods.Add(33*Periods[0] + .67*SmoothPeriods[0]); if (I1s[0] != 0) Phases.Add(Math.Atan(Q1s[0] / I1s[0])); double DeltaPhase = Phases[1] - Phases[0]; if (DeltaPhase < 1) DeltaPhase = 1; double alpha = MAMA_FastLimit / DeltaPhase; if (alpha < MAMA_SlowLimit) alpha = MAMA_SlowLimit; MAMAs.Add(alpha*Prices[0] + (1 - alpha)*MAMAs[0]); FAMAs.Add(.5*alpha*MAMAs[0] + (1 - .5*alpha)*FAMAs[0]); if (MAMAs[0] > FAMAs[0]) { _trend_dir = 1; } else if (MAMAs[0] < FAMAs[0]) { _trend_dir = -1; } if (MAMAs[0] > MAMAs[1]) { _mama_dir = 1; } else if (MAMAs[0] < MAMAs[1]) { _mama_dir = -1; } // ********************************************************************************************************* // Update chart if (Math.Abs(FAMAs[0] - Prices[0]) < 5) { Plot("MAMA", "price", Prices[0]); Plot("MAMA", "MAMA", MAMAs[0]); Plot("MAMA", "FAMA", FAMAs[0]); } // Order logic / (simple) risk management decimal pps = ((_price - _oldprice)/_oldprice)*100; if (pps <= -2.5M || _trend_dir != _old_dir) { // if direction is wrong // End position Liquidate(_ticker); } if (!Portfolio.HoldStock) { int quantity = (int)Math.Floor(Portfolio.Cash / data.Close); if (_trend_dir != _old_dir) { if (quantity > 0) Order(_ticker, _trend_dir*quantity); _oldprice = _price; _old_dir = _trend_dir; } } } } }