// ------------------------------------------------------------------------------- // Exploits persistent/anti-peristent trend trading. // Twist? Acts contrary!. // Looks up N past bars. // If at least 66% (empirical) of N bars followed previous bar's direction, we are in persistent mode. // If at least 66% of N bars went against previous bar's direction, we are in anti-persistent mode. // If we are in persistent mode - open opposite to previous bar or keep a position which is opposite to previous bar. // If we are in anti-persistent mode - open in direction of previous bar or keep a position which is in direction of previous bar. // Yes, we trade assuming a change in persistence. // Prone to weekend gaps. // Copyright 2013, EarnForex.com // http://www.earnforex.com // ------------------------------------------------------------------------------- using System; using System.Linq; using cAlgo.API; using cAlgo.API.Requests; namespace cAlgo.Robots { [Robot] public class PersistentAnti : Robot { [Parameter(DefaultValue = 10, MinValue = 2)] public int N { get; set; } [Parameter(DefaultValue = 0.66, MinValue = 0, MaxValue = 1)] public double Ratio { get; set; } [Parameter(DefaultValue = 1, MinValue = 0, MaxValue = 1)] public int Reverse { get; set; } [Parameter(DefaultValue = 0, MinValue = 0, MaxValue = 1)] public int MM { get; set; } [Parameter(DefaultValue = 10000, MinValue = 0)] public int Volume { get; set; } [Parameter(DefaultValue = 100, MinValue = 0)] public int Slippage { get; set; } [Parameter(DefaultValue = 1000000, MinValue = 0)] public int MaxPositionSize { get; set; } [Parameter(DefaultValue = "PersistentAnti")] public string Comment { get; set; } private bool HaveLongPosition; private bool HaveShortPosition; private Position position { get { return Account.Positions.FirstOrDefault(pos => ((pos.Label == Comment) && (pos.SymbolCode == Symbol.Code))); } } protected override void OnBar() { if (Trade.IsExecuting) return; int Persistence = 0; int Antipersistence = 0; int last = MarketSeries.Close.Count - 2; // Cycle inside the N-bar range for (int i = last; i > last - N; i--) // i is always pointing at a bar inside N-range. { //string s = ""; // Previous bar was bullish if (MarketSeries.Close[i - 1] > MarketSeries.Open[i - 1]) { // Current bar is bullish if (MarketSeries.Close[i] > MarketSeries.Open[i]) { Persistence++; //s = "Persistent"; } // Current bar is bearish else if (MarketSeries.Close[i] < MarketSeries.Open[i]) { Antipersistence++; //s = "Antipersistent"; } //Print(MarketSeries.OpenTime[i] + " Open: " + MarketSeries.Open[i] + " Close: " + MarketSeries.Close[i] + " " + s + " Previous - Bullish @ " + MarketSeries.OpenTime[i - 1]); } // Previous bar was bearish else if (MarketSeries.Close[i - 1] < MarketSeries.Open[i - 1]) { // Current bar is bearish if (MarketSeries.Close[i] < MarketSeries.Open[i]) { Persistence++; //s = "Persistent"; } // Current bar is bullish else if (MarketSeries.Close[i] > MarketSeries.Open[i]) { Antipersistence++; //s = "Antipersistent"; } //Print(MarketSeries.OpenTime[i] + " Open: " + MarketSeries.Open[i] + " Close: " + MarketSeries.Close[i] + " " + s + " Previous - Bearish @ " + MarketSeries.OpenTime[i - 1]); } // NOTE: If previous or current bar is flat, neither persistence or anti-persistence point is scored, // which means that we are more likely to stay out of the market. } //Print("P: " + Persistence + " A: " + Antipersistence + " Threshold: " + (Ratio * N) + " Previous bar: " + MarketSeries.OpenTime[last] + " Open: " + MarketSeries.Open[last] + " Close: " + MarketSeries.Close[last]); // Check what position is currently open GetPositionStates(); if (((Persistence > Ratio * N) && (Reverse == 1)) || ((Antipersistence > Ratio * N) && (Reverse == 0))) { // If previous bar was bullish, go short. Remember: we are acting on the contrary! if (MarketSeries.Close[last] > MarketSeries.Open[last]) { if (HaveLongPosition) ClosePrevious(); if (!HaveShortPosition) fSell(); } // If previous bar was bearish, go long. else if (MarketSeries.Close[last] < MarketSeries.Open[last]) { if (HaveShortPosition) ClosePrevious(); if (!HaveLongPosition) fBuy(); } } else if (((Persistence > Ratio * N) && (Reverse == 0)) || ((Antipersistence > Ratio * N) && (Reverse == 1))) { // If previous bar was bullish, go long. if (MarketSeries.Close[last] > MarketSeries.Open[last]) { if (HaveShortPosition) ClosePrevious(); if (!HaveLongPosition) fBuy(); } // If previous bar was bearish, go short. else if (MarketSeries.Close[last] < MarketSeries.Open[last]) { if (HaveLongPosition) ClosePrevious(); if (!HaveShortPosition) fSell(); } } // If no Persistence or Antipersistence is detected, just close current position. else if ((HaveLongPosition) || (HaveShortPosition)) ClosePrevious(); } private void GetPositionStates() { if (position != null) { if (position.TradeType == TradeType.Buy) { HaveLongPosition = true; HaveShortPosition = false; return; } else if (position.TradeType == TradeType.Sell) { HaveLongPosition = false; HaveShortPosition = true; return; } } HaveLongPosition = false; HaveShortPosition = false; } private void ClosePrevious() { if (position == null) return; Trade.Close(position); } private void fBuy() { var request = new MarketOrderRequest(TradeType.Buy, VolumeOptimized()) { Label = Comment }; Trade.Send(request); } private void fSell() { var request = new MarketOrderRequest(TradeType.Sell, VolumeOptimized()) { Label = Comment }; Trade.Send(request); } private int VolumeOptimized() { if (MM == 0) return (Volume); int TVolume = (int)Math.Round(1.5 * Account.Balance, 0); int NO = 0; if (TVolume > MaxPositionSize) TVolume = MaxPositionSize; return(TVolume); } } }