Overall Statistics
Total Trades
552
Average Win
2.15%
Average Loss
-1.81%
Compounding Annual Return
8.748%
Drawdown
15.700%
Expectancy
0.252
Net Profit
223.831%
Sharpe Ratio
0.734
Loss Rate
43%
Win Rate
57%
Profit-Loss Ratio
1.19
Alpha
0.074
Beta
0.002
Annual Standard Deviation
0.1
Annual Variance
0.01
Information Ratio
0.135
Tracking Error
0.21
Treynor Ratio
44.089
Total Fees
$1331.16
namespace QuantConnect 
{   
    /*
    *   John Ehlers' MESA
    *   (programmed by Jean-Paul van Brakel)
    */
    public class BasicTemplateAlgorithm : QCAlgorithm
    {
    	public string _ticker = "SPY";			// which stock ticker
    	public static int MESA_length = 9;		// indicator length
    	public static decimal _limit = 0.85M; 	// threshold for anti-trend liquidation
		private readonly RollingWindow<double> Prices = new RollingWindow<double>(MESA_length);
		private Chart plotter;
		decimal _oldprice = 100000;
		decimal _price;
		decimal _oldsine;
		decimal _sine;
		decimal _lead;
		int _dir = 0;
    	
        public override void Initialize() 
        {
            //Start and End Date range for the backtest:
            SetStartDate(2000, 1, 1);         
            SetEndDate(2014, 1, 1);
            SetCash(25000);
            AddSecurity(SecurityType.Equity, _ticker, Resolution.Daily);
            
            plotter = new Chart("MESA", 				ChartType.Overlay);
			plotter.AddSeries(new Series("MESA sine", 	SeriesType.Line));
			plotter.AddSeries(new Series("MESA lead", 	SeriesType.Line));
			AddChart(plotter);
        }

        public void OnData(TradeBars data) 
        {   
        	Prices.Add((double)(data[_ticker].High + data[_ticker].Low)/2);
        	_price = data[_ticker].Close;
        	if (!Prices.IsReady) return;
        	
        	// MESA
			// *********************************************************************************************************
            double realPart = 0;
            double imagPart = 0;
            for (int i = 0; i < MESA_length; i++) {
            	double temp = Prices[i];
            	realPart = realPart + temp*Math.Cos(2*Math.PI*i/MESA_length);
            	imagPart = imagPart + temp*Math.Sin(2*Math.PI*i/MESA_length);
            }
            
            double phase1 = 0;
            if (Math.Abs(realPart) > 0.001) {
            	phase1 = Math.Atan(imagPart/realPart);
            } else {
            	phase1 = (Math.PI / 2*Math.Sign(imagPart));
            }
            double phase2 = 0;
            if (realPart < 0) {
            	phase2 = phase1 + Math.PI;
            } else {
            	phase2 = phase1;
            }
            double phase = 0;
            if (phase2 < 0) {
            	phase = phase2 + 2*Math.PI;
            } else if (phase2 > 2*Math.PI) {
            	phase = phase2 - 2*Math.PI;
            } else {
            	phase = phase2;
            }
			_oldsine = _sine;
            _sine = (decimal) Math.Cos(phase);
            _lead = (decimal) Math.Cos(phase+Math.PI/4);
            
            int _old_dir = _dir;
            if (_lead < _sine && _dir != -1) {
            	_dir = -1;
            } else if (_lead > _sine && _dir != 1) {
            	_dir = 1;
            }
			// *********************************************************************************************************
            
            // Update chart
            Plot("MESA", "MESA sine", _sine+90);
            Plot("MESA", "MESA lead", _lead+90);
            
            // Order logic / (simple) risk management
            decimal pps = ((_price - _oldprice)/_oldprice)*100;
            if (pps >= 4.5M || pps < -2.0M || _dir != _old_dir ||    	// if P/L crosses boundaries
            	(_sine < _limit && _sine > _oldsine && _dir == -1) || 	// if direction is wrong
            	(_sine > _limit && _sine < _oldsine && _dir == 1)) {  	// if direction is wrong
            	// End position
            	Liquidate(_ticker);
            }
            
            if (!Portfolio.HoldStock) {
            	int quantity = (int)Math.Floor(Portfolio.Cash / data[_ticker].Close);
	            if (_dir != _old_dir) {
	            	if (quantity > 0)
	            		Order(_ticker,  _dir*quantity);
	            	_oldprice = _price;
	            }
            }
        }
    }
}