// Goblin BiPolar Edition v.1.0
// by bluto @ www.forex-tsd.com
// 12/20/2006
//
// Here's a roughly cobbled version of Goblin that supports two EA routines in one - a buy side and a sell side running concurrently.
// Although effective, the code isn't the most modular at this point.  If the concept proves to be viable, I'll continue further
// development to optimize shared subroutines between the two sub-EA routines.  For now...play, test & be bodaceous!
//
// Modifications by alassio:
// - Determine lot size of individual orders
// - Scale lot sizes by account equity for compounding (replaces previous mm)
// - Collect winner/loser statistics
// - Allow usage of progressions after losers (experimental)
//

extern string    FixedLotsFeature = "** Determine lot size of individual orders **";
extern double    FixedLotsOrder1 = 2;
extern double    FixedLotsOrder2 = 2;
extern double    FixedLotsOrder3 = 1;
extern double    FixedLotsOrder4 = 3;
extern double    FixedLotsOrder5 = 4;
extern double    FixedLotsOrder6 = 5;
extern double    FixedLotsOrder7 = 0;
extern double    FixedLotsOrder8 = 0;
extern double    FixedLotsOrder9 = 0;
extern double    FixedLotsOrderLast = 0;

extern string    DynamicLotsFeature = "** Scale lots by account size for compounding **";
extern bool      UseDynamicLots = true;
extern double    LotBaseEquity = 50000;
extern double    LotBaseSize = 1;

extern string    StatisticsFeature = "** Collect winner/loser statistics **";
extern double    LoserLimit = -1000;
extern double    KellyFactor = 0.25;

extern string    ProgressionFeature = "** Use lot size progression after losers **";
extern bool      UseProgression = false;
extern bool      UseGlobalProg = true; // Same progression for bus/sell orders
extern int       ProgressionModel = 2; // 1 = Dahl progression, 2 = reverse Dahl progression
extern int       MaxProgStep = 12;
extern bool      UseCycleProgSteps = false;

extern string    EntryFeature = "** Select entry signal parameters **";
extern bool      UseRSX = false;
extern bool      UseConservativeRSX_Signals=false;        // If true, we use tighter RSX 70/30 rules
extern int       RSX_Period=17;
extern int       RSX_Timeframe=60;
extern bool      UseJMATrend = true;                                                 
extern int       JMAPeriod = 28;
extern int       JMALag = 2;
extern double    JMAPointDiff = 2;
extern bool      UseSMATrendFilter=false;
extern int       TrendFilterSMATimeFrame=60;
extern int       TrendFilterFastSMAPeriod=65;
extern int       TrendFilterMediumSMAPeriod=20;
extern int       TrendFilterSlowSMAPeriod=7;

extern string    LongTradeParms = "** Goblin Buy Side Parameters **";
extern double    LongTakeProfit = 10;           // Profit Goal for the latest order opened
extern double    LongInitialStop = 10;          // StopLoss
extern double    LongTrailingStop = 0;          // Pips to trail the StopLoss
extern int       LongMaxTrades=6;               // Maximum number of orders to open
extern int       LongPips=5;                    // Distance in Pips from one order to another
extern int       LongSecureProfit=0;            // If profit made is bigger than SecureProfit we close the orders
extern bool      LongAccountProtection=false;   // If one the account protection will be enabled, 0 is disabled
extern int       LongOrderstoProtect=0;         // This number subtracted from LongMaxTrades is the number of open orders to enable the account protection.
                                                // Example: (LongMaxTrades=10) minus (OrderstoProtect=3)=7 orders need to be open before account protection is enabled.
                                                
extern string    ShortTradeParms = "** Goblin Sell Side Parameters **";
extern double    ShortTakeProfit = 10;          // Profit Goal for the latest order opened
extern double    ShortInitialStop = 10;         // StopLoss
extern double    ShortTrailingStop = 0;         // Pips to trail the StopLoss
extern int       ShortMaxTrades=6;              // Maximum number of orders to open
extern int       ShortPips=5;                   // Distance in Pips from one order to another
extern int       ShortSecureProfit=0;           // If profit made is bigger than SecureProfit we close the orders
extern bool      ShortAccountProtection=false;  // If one the account protection will be enabled, 0 is disabled
extern int       ShortOrderstoProtect=0;        // This number subtracted from LongMaxTrades is the number of open orders to enable the account protection.
                                                // Example: (LongMaxTrades=10) minus (OrderstoProtect=3)=7 orders need to be open before account protection is enabled. 
                                                 
                                                 
// Global internal parameters used by LongGoblin() buy order module:   
                        
int              LongMagicNumber = 0;            // Magic number for the long orders placed                              
int              L_OpenOrders=0;
int              L_Count=0;
int              L_Slippage=5;
double           L_sl=0;
double           L_tp=0;
double           BuyPrice=0;
double           L_OrderLotSize=0;
int              L_Mode=0;
int              L_OrderType=0;
bool             L_ContinueOpening=true;
double           L_LastPrice=0;
int              L_PreviousOpenOrders=0;
double           L_Profit=0;
int              L_LastTicket=0;
int              L_LastType=0;
double           L_LastClosePrice=0;
double           L_LastLots=0;
double           L_PipValue=0;

double           L_OldProfit = 0;
int              L_ProgStep = 0;
double           L_ProgFactor = 1;
int              L_Winners = 0;
int              L_Losers = 0;
double           L_Balance = 0;
double           L_AccumulatedProfit = 0;

// Global internal parameters used by ShortGoblin() sell order module:
   
int              ShortMagicNumber = 0;           // Magic number for the short orders placed                            
int              S_OpenOrders=0;
int              S_Count=0;
int              S_Slippage=5;
double           S_sl=0;
double           S_tp=0;
double           SellPrice=0;
double           S_OrderLotSize=0;
int              S_Mode=0;
int              S_OrderType=0;
bool             S_ContinueOpening=true;
double           S_LastPrice=0;
int              S_PreviousOpenOrders=0;
double           S_Profit=0;
int              S_LastTicket=0;
int              S_LastType=0;
double           S_LastClosePrice=0;
double           S_LastLots=0;
double           S_PipValue=0;

double           S_OldProfit = 0;
int              S_ProgStep = 0;
double           S_ProgFactor = 1;
int              S_Winners = 0;
int              S_Losers = 0;
double           S_Balance = 0;
double           S_AccumulatedProfit = 0;

// Global internal shared parameters

double           G_MinLotSize=0;
double           G_MaxLotSize=0;
double           G_LotStep=0;
double           G_Decimals=0;
int              G_AcctLeverage=0;
int              G_CurrencyLotSize=0;
double           G_OrderLotSize=0;
int              G_Count=0;
int              G_Slippage=5;

int              G_ProgStep = 0;
double           progSteps[15];
int              maxWinPeriod = -1;
int              minWinPeriod = -1;
int              numWinPeriods = 0;
double           avgWinPeriod = 0;
int              numConsecutiveLosers = 0;
int              maxConsecutiveLosers = 0;
int              winPeriod = 0;
bool             lastWinner = true;
int              ordWinners[20];
double           ordProfits[20];
double           totalLoss = 0;
bool             initialized = false;

double           winPercent = 100;
double           wlr = 0;
double           avgProfit = 0;
double           avgLoss = 0;
double           expectedProfit = 0;
double           expectedProfitPercent = 100;
double           contracts = 0;
double           kelly = 0;

int init()
{
  initProgression(ProgressionModel);
  
// For those of us tired of messing around assigning annoying but essential magic numbers.
   
   if (Symbol()=="AUDCADm" || Symbol()=="AUDCAD") {LongMagicNumber=100001;ShortMagicNumber=200001;}
   if (Symbol()=="AUDJPYm" || Symbol()=="AUDJPY") {LongMagicNumber=100002;ShortMagicNumber=200002;}
   if (Symbol()=="AUDNZDm" || Symbol()=="AUDNZD") {LongMagicNumber=100003;ShortMagicNumber=200003;}
   if (Symbol()=="AUDUSDm" || Symbol()=="AUDUSD") {LongMagicNumber=100004;ShortMagicNumber=200004;}
   if (Symbol()=="CHFJPYm" || Symbol()=="CHFJPY") {LongMagicNumber=100005;ShortMagicNumber=200005;}
   if (Symbol()=="EURAUDm" || Symbol()=="EURAUD") {LongMagicNumber=100006;ShortMagicNumber=200006;}
   if (Symbol()=="EURCADm" || Symbol()=="EURCAD") {LongMagicNumber=100007;ShortMagicNumber=200007;}
   if (Symbol()=="EURCHFm" || Symbol()=="EURCHF") {LongMagicNumber=100008;ShortMagicNumber=200008;}
   if (Symbol()=="EURGBPm" || Symbol()=="EURGBP") {LongMagicNumber=100009;ShortMagicNumber=200009;}
   if (Symbol()=="EURJPYm" || Symbol()=="EURJPY") {LongMagicNumber=100010;ShortMagicNumber=200010;}
   if (Symbol()=="EURUSDm" || Symbol()=="EURUSD") {LongMagicNumber=100011;ShortMagicNumber=200011;}
   if (Symbol()=="GBPCHFm" || Symbol()=="GBPCHF") {LongMagicNumber=100012;ShortMagicNumber=200012;}   
   if (Symbol()=="GBPJPYm" || Symbol()=="GBPJPY") {LongMagicNumber=100013;ShortMagicNumber=200013;}
   if (Symbol()=="GBPUSDm" || Symbol()=="GBPUSD") {LongMagicNumber=100014;ShortMagicNumber=200014;}
   if (Symbol()=="NZDJPYm" || Symbol()=="NZDJPY") {LongMagicNumber=100015;ShortMagicNumber=200015;}
   if (Symbol()=="NZDUSDm" || Symbol()=="NZDUSD") {LongMagicNumber=100016;ShortMagicNumber=200016;}
   if (Symbol()=="USDCHFm" || Symbol()=="USDCHF") {LongMagicNumber=100017;ShortMagicNumber=200017;}
   if (Symbol()=="USDJPYm" || Symbol()=="USDJPY") {LongMagicNumber=100018;ShortMagicNumber=200018;}
   if (Symbol()=="USDCADm" || Symbol()=="USDCAD") {LongMagicNumber=100019;ShortMagicNumber=200019;}
   if (LongMagicNumber==0) {LongMagicNumber = 100999;}   
   if (ShortMagicNumber==0) {ShortMagicNumber = 200999;}   
   return(0);
   
  }


int start()
{

  if (!initialized)
  {
   for(int i = 0; i < 20; i++)
   {
     ordWinners[i] = 0;
     ordProfits[i] = 0;
   }
   initialized = true;
  }
  
//====================================================== Begin Top Level Command Module ============================================================  
 
// Global equity/risk based lot sizer

G_AcctLeverage = AccountLeverage();
G_MinLotSize = MarketInfo(Symbol(),MODE_MINLOT);
G_MaxLotSize = MarketInfo(Symbol(),MODE_MAXLOT);
G_LotStep = MarketInfo(Symbol(),MODE_LOTSTEP);
G_CurrencyLotSize = MarketInfo(Symbol(),MODE_LOTSIZE);

if(G_LotStep == 0.01) {G_Decimals = 2;}
if(G_LotStep == 0.1) {G_Decimals = 1;}

if (UseDynamicLots)
{
   if (G_OrderLotSize <= 0)
   {
      G_OrderLotSize = StrToDouble(DoubleToStr(LotBaseSize*AccountEquity()/LotBaseEquity,G_Decimals));
   }
} else {
  G_OrderLotSize = LotBaseSize;
}

if (G_OrderLotSize < G_MinLotSize) {G_OrderLotSize = G_MinLotSize;}
if (G_OrderLotSize > G_MaxLotSize) {G_OrderLotSize = G_MaxLotSize;}
 
    
   LongGoblin();
   ShortGoblin();
   
   if (!IsTesting())
   {
      string msg =
         "Avg prof "+DoubleToStr(avgProfit,2)+", avg loss "+DoubleToStr(avgLoss,2)+", w/l "+DoubleToStr(wlr,2)+
          "%, prob "+DoubleToStr(winPercent,2)+"%"+
          "; Exp "+DoubleToStr(expectedProfit,2)+" ("+DoubleToStr(expectedProfitPercent,2)+"%)"+
          "; Kelly "+DoubleToStr(kelly,2)+", # "+DoubleToStr(contracts,2)+"";
   
      Comment("\nBUY CYCLE : Orders Open = ",L_OpenOrders," Profit = ",DoubleToStr(L_Profit,2)," +/-",
              "\nSELL CYCLE: Orders Open = ",S_OpenOrders," Profit = ",DoubleToStr(S_Profit,2)," +/-",
              "\n\n"+msg);
   }

   return(0);
  }  
   
//====================================================== End Of Top Level Command Module ============================================================<<

void initProgression(int model)
{
   if (model == 1)
   {
      // Increasing lot size with every winner, decrease again when losers become more likely
      progSteps[0] = 1;
      progSteps[1] = 1;
      progSteps[2] = 1.5;
      progSteps[3] = 1.5;
      progSteps[4] = 2;
      progSteps[5] = 2;
      progSteps[6] = 3;
      progSteps[7] = 3;
      progSteps[8] = 2;
      progSteps[9] = 2;
      progSteps[10] = 1.5;
      progSteps[11] = 1.5;
      progSteps[12] = 1;
      progSteps[13] = 1;
   } else {
      // Start with high factor to recover previous loss and the decrease lot size again
      progSteps[0] = 5;
      progSteps[1] = 3;
      progSteps[2] = 3;
      progSteps[3] = 2;
      progSteps[4] = 2;
      progSteps[5] = 1.5;
      progSteps[6] = 1.5;
      progSteps[7] = 1;
      progSteps[8] = 1;
      progSteps[9] = 1;
      progSteps[10] =1;
      progSteps[11] = 1;
      progSteps[12] = 1;
      progSteps[13] = 1;
   }
}

void setWinner(int orders,bool long,bool winner,double amount)
{
   if (UseDynamicLots)
   {
      amount = amount/G_OrderLotSize;
   }
   if(UseProgression)
   {
      if (long)
      {
         amount = amount/L_ProgFactor;
      } else {
         amount = amount/S_ProgFactor;
      }
   }
   if (winner && orders >= 0 && orders < 20)
   {
      ordWinners[orders]++;
      ordProfits[orders] = ordProfits[orders]+amount;
   } else
   if (!winner)
   {
      totalLoss = totalLoss+amount;
   }
   if (long)
   {
      if (winner)
      {
         L_Winners++;
      } else {
         L_Losers++;
      }
   } else 
   {
      if (winner)
      {
         S_Winners++;
      } else {
         S_Losers++;
      }
   }
   if (winner)
   {
      if (lastWinner)
      {
         winPeriod++;
      } else {
         winPeriod = 1;
         if (numConsecutiveLosers > maxConsecutiveLosers)
         {
            maxConsecutiveLosers = numConsecutiveLosers;
         }
         numConsecutiveLosers = 0;
      }
   } else {
      numConsecutiveLosers++;
      if (lastWinner)
      {
         // Run ended now
         if (winPeriod > maxWinPeriod)
         {
            maxWinPeriod = winPeriod;
         }
         if (winPeriod < minWinPeriod || minWinPeriod < 0)
         {
            minWinPeriod = winPeriod;
         }
         if (numWinPeriods > 0)
         {
            avgWinPeriod = (avgWinPeriod*numWinPeriods+winPeriod)/(numWinPeriods+1);
            numWinPeriods++;
         } else {
            avgWinPeriod = winPeriod;
            numWinPeriods = 1;
         }
      } else {
         winPeriod = 0;
      }
   }
   lastWinner = winner;
}

void LogStatistic()
{
   int winners = L_Winners+S_Winners;
   int losers = L_Losers+S_Losers;
   double losePercent = 0;
   if (losers > 0)
   {
      avgLoss = totalLoss/losers;
   }
   double avgProfit1 = ordProfits[1];
   if (ordWinners[1] > 0)
   {
      avgProfit1 = avgProfit1/ordWinners[1];
   }
   double avgProfit2 = ordProfits[2];
   if (ordWinners[2] > 0)
   {
      avgProfit2 = avgProfit2/ordWinners[2];
   }
   double avgProfit3 = ordProfits[3];
   if (ordWinners[3] > 0)
   {
      avgProfit3 = avgProfit3/ordWinners[3];
   }
   double avgProfit4 = ordProfits[4];
   if (ordWinners[4] > 0)
   {
      avgProfit4 = avgProfit4/ordWinners[4];
   }
   double avgProfit5 = ordProfits[5];
   if (ordWinners[5] > 0)
   {
      avgProfit5 = avgProfit5/ordWinners[5];
   }
   double avgProfit6 = ordProfits[6];
   if (ordWinners[6] > 0)
   {
      avgProfit6 = avgProfit6/ordWinners[6];
   }
   double avgProfit7 = ordProfits[7];
   if (ordWinners[7] > 0)
   {
      avgProfit7 = avgProfit7/ordWinners[7];
   }
   double avgProfit8 = ordProfits[8];
   if (ordWinners[8] > 0)
   {
      avgProfit8 = avgProfit8/ordWinners[8];
   }
   double avgProfit9 = ordProfits[9];
   if (ordWinners[9] > 0)
   {
      avgProfit9 = avgProfit9/ordWinners[9];
   }
   double avgProfit10 = ordProfits[10];
   if (ordWinners[10] > 0)
   {
      avgProfit10 = avgProfit10/ordWinners[10];
   }
   if (winners+losers > 0)
   {
      winPercent = 100.0*winners/(winners+losers);
      losePercent = 100.0*losers/(winners+losers);
      for(int i = 1; i <= 10; i++)
      {
         avgProfit += ordProfits[i];
      }
      expectedProfit = (totalLoss+avgProfit)/(winners+losers);
      if (winners > 0)
      {
         avgProfit = avgProfit/winners;
      }
      if (avgLoss < 0)
      {
         wlr = 100.0*avgProfit/(-avgLoss);
         expectedProfitPercent = 100*expectedProfit/(-avgLoss);
         if (wlr > 0)
         {
            kelly = KellyFactor*(winPercent/100.0-(100.0-winPercent)/wlr);
         }
         contracts = LotBaseEquity*kelly/(-avgLoss);
      }
   }
   Print("Buy winners "+L_Winners+",losers "+L_Losers+"; Sell winners "+S_Winners+", losers "+S_Losers+
         "; Total winners "+winners+" ("+DoubleToStr(winPercent,0)+"%), losers "+losers+" ("+DoubleToStr(losePercent,0)+"%)"+
         "; Longest run "+maxWinPeriod+", shortest run "+minWinPeriod+", avg run "+DoubleToStr(avgWinPeriod,1)+
         ", max cons. losers "+maxConsecutiveLosers);
   Print("Losers: "+losers+" ("+DoubleToStr(avgLoss,2)+"),"+
         "Winners 1: "+ordWinners[1]+" ("+DoubleToStr(avgProfit1,2)+"), "+
         "2: "+ordWinners[2]+" ("+DoubleToStr(avgProfit2,2)+"), "+
         "3: "+ordWinners[3]+" ("+DoubleToStr(avgProfit3,2)+"), "+
         "4: "+ordWinners[4]+" ("+DoubleToStr(avgProfit4,2)+"), "+
         "5: "+ordWinners[5]+" ("+DoubleToStr(avgProfit5,2)+"), "+
         "6: "+ordWinners[6]+" ("+DoubleToStr(avgProfit6,2)+"), "+
         "7: "+ordWinners[7]+" ("+DoubleToStr(avgProfit7,2)+"), "+
         "8: "+ordWinners[8]+" ("+DoubleToStr(avgProfit8,2)+"), "+
         "9: "+ordWinners[9]+" ("+DoubleToStr(avgProfit9,2)+"), "+
         "10: "+ordWinners[10]+" ("+DoubleToStr(avgProfit10,2)+")");
   Print("Avg profit "+DoubleToStr(avgProfit,2)+", avg loss "+DoubleToStr(avgLoss,2)+", w/l "+DoubleToStr(wlr,2)+
         "%, win prob "+DoubleToStr(winPercent,2)+"%"+
         "; Exp "+DoubleToStr(expectedProfit,2)+" ("+DoubleToStr(expectedProfitPercent,2)+"%)"+
         "; Kelly "+DoubleToStr(kelly,2)+", # "+DoubleToStr(contracts,2)+"");
}


//====================================================== Begin Buy Order Processing SubRoutine ======================================================<<

void LongGoblin()
  {
   L_Profit=0;
   L_OpenOrders=0;
   if (L_Balance <= 0)
   {
      L_Balance = AccountBalance();
   }
   if (S_PreviousOpenOrders < 1)
   {
     L_AccumulatedProfit = 0;
   }
   for(L_Count=0;L_Count<OrdersTotal();L_Count++)   
   {
    OrderSelect(L_Count, SELECT_BY_POS, MODE_TRADES);
    if (OrderSymbol()==Symbol() && OrderMagicNumber() == LongMagicNumber) {L_OpenOrders++;L_Profit=L_Profit+OrderProfit();}
   }     
   
   L_PipValue = MarketInfo(Symbol(),MODE_TICKVALUE);
   if (L_PipValue==0) { L_PipValue=5; }
   
   if (L_PreviousOpenOrders>L_OpenOrders) 
   {	  
	 for(L_Count=OrdersTotal();L_Count>=0;L_Count--)
	  {     
      OrderSelect(L_Count, SELECT_BY_POS, MODE_TRADES);
	   if (OrderSymbol()==Symbol() && OrderMagicNumber() == LongMagicNumber && OrderType() == OP_BUY) 
	    {
        int m_Ticket = OrderTicket();
	     OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),L_Slippage,Blue);
		  Print("Closing Buy Order ",m_Ticket);
		  return(0);
		 }
	  }
	  L_OldProfit = AccountBalance()-L_Balance-S_AccumulatedProfit;
	  if (S_AccumulatedProfit > 0)
	  {
	     Print("Subtracting accumulated sell profit "+S_AccumulatedProfit);
	  }
	  if (S_PreviousOpenOrders > 0)
	  {
	     L_AccumulatedProfit += L_OldProfit;
	  } else {
	     L_AccumulatedProfit = 0;
	  }
	  if (MaxProgStep > 12)
	  {
	    MaxProgStep = 12;
	  }
	  if (UseGlobalProg)
	  {
	    L_ProgStep = G_ProgStep;
	  }
	  if (L_OldProfit < LoserLimit*G_OrderLotSize)
	  {
	    // Loser
	    setWinner(L_PreviousOpenOrders,true,false,L_OldProfit);
	    L_ProgStep = 0;
	  } else {
	    // Winner
	    setWinner(L_PreviousOpenOrders,true,true,L_OldProfit);
	    L_ProgStep = L_ProgStep+1;
	    if (L_ProgStep > MaxProgStep)
	    {
	      L_ProgStep = MaxProgStep;
	      if (UseCycleProgSteps)
	      {
	        L_ProgStep = 0;
	      }
	    }
	  }
	  if (UseGlobalProg)
	  {
	    G_ProgStep = L_ProgStep;
	    S_ProgFactor = progSteps[G_ProgStep];
	  }
	  L_ProgFactor = progSteps[L_ProgStep];
	  if (L_ProgFactor <= 0)
	  {
	    L_ProgFactor = 1;
	  }
	  if (UseProgression)
	  {
	    if (L_OldProfit < LoserLimit*G_OrderLotSize)
	    {
	      Print("Last buy trade was a loser, factor is now "+L_ProgFactor+" (step "+L_ProgStep+")");
	    } else {
	      Print("Last buy trade was a winner, factor is now "+L_ProgFactor+" (step "+L_ProgStep+")");
	    }
	  }
	  LogStatistic();
   }

   L_PreviousOpenOrders=L_OpenOrders;
   if (L_OpenOrders>=LongMaxTrades) 
    {
	  L_ContinueOpening=False;
    } else {
	  L_ContinueOpening=True;
    }

   if (L_LastPrice==0) 
    {
	  for(L_Count=0;L_Count<OrdersTotal();L_Count++)
	   {	
       OrderSelect(L_Count, SELECT_BY_POS, MODE_TRADES);
	    if (OrderSymbol()==Symbol() && OrderMagicNumber() == LongMagicNumber && OrderType() == OP_BUY) 
		  {
			L_LastPrice=OrderOpenPrice();
		   L_OrderType=2;
		  }
	   }
    }

   if (UseDynamicLots && !L_ContinueOpening)
   {
      G_OrderLotSize = StrToDouble(DoubleToStr(LotBaseSize*AccountEquity()/LotBaseEquity,G_Decimals));
   }
   
   if (L_OpenOrders<1) {L_OrderType=OpenOrdersBasedOnTrendRSX();}
 
// Here comes the fun part we all waited for where we update those trailing stops....yippeekyeah!!

   for(L_Count=OrdersTotal();L_Count>=0;L_Count--)
    {
     OrderSelect(L_Count, SELECT_BY_POS, MODE_TRADES);
     if (OrderSymbol() == Symbol() && OrderMagicNumber() == LongMagicNumber && OrderType()== OP_BUY)  
      {	
       if (LongTrailingStop > 0 && (Bid-OrderOpenPrice()>=(LongTrailingStop+LongPips)*Point) &&  (OrderStopLoss()<(Bid-Point*LongTrailingStop)) )
        {				   
	      OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*LongTrailingStop,OrderClosePrice()+LongTakeProfit*Point+LongTrailingStop*Point,800,Yellow);
         return(0);
        } 
	   }
  	 }
   
   L_Profit=0;
   L_LastTicket=0;
   L_LastType=0;
	L_LastClosePrice=0;
	L_LastLots=0;	
	for(L_Count=0;L_Count<OrdersTotal();L_Count++)
	{
    OrderSelect(L_Count, SELECT_BY_POS, MODE_TRADES);
    if (OrderSymbol()==Symbol() && OrderMagicNumber() == LongMagicNumber && OrderType()==OP_BUY) 
	  {			
  	   L_LastTicket=OrderTicket();
		L_LastType=OP_BUY; 
		L_LastClosePrice=OrderClosePrice();
		L_LastLots=OrderLots();
		L_Profit=L_Profit+OrderProfit();	
	  }
   }
   L_OldProfit = L_Profit;
	
   if (L_OpenOrders>=(LongMaxTrades-LongOrderstoProtect) && LongAccountProtection==true) 
    {	    
     if (L_Profit>=LongSecureProfit) 
      {
       OrderClose(L_LastTicket,L_LastLots,L_LastClosePrice,L_Slippage,Yellow);		 
       L_ContinueOpening=False;
       return(0);
      }
    }
      
   if (L_OpenOrders > 0 && L_OpenOrders < LongMaxTrades && ((L_LastPrice-Ask)>=LongPips*Point))
   {
      if (L_OrderType==2 && L_ContinueOpening)
      {
         //Print("Ready to open buy order at "+Ask);
      } else {
         Print("BLOCKED buy order at "+Ask);
      }
   }
      
   if (L_OrderType==2 && L_ContinueOpening && ((L_LastPrice-Ask)>=LongPips*Point || L_OpenOrders<1) ) 
    {  		
     BuyPrice=Ask;
     L_LastPrice=0;
     if (LongTakeProfit==0) { L_tp=0; }
      else { L_tp=BuyPrice+LongTakeProfit*Point; }	
     if (LongInitialStop==0)  { L_sl=0; }
      else { L_sl=NormalizeDouble(BuyPrice-LongInitialStop*Point - (LongMaxTrades-L_OpenOrders)*LongPips*Point, Digits); }
       L_OrderLotSize=G_OrderLotSize;			
            if (L_OpenOrders <= 0)
            {
               L_OrderLotSize = FixedLotsOrder1;
            } else
            if (L_OpenOrders == 1)
            {
               L_OrderLotSize = FixedLotsOrder2;
            } else
            if (L_OpenOrders == 2)
            {
               L_OrderLotSize = FixedLotsOrder3;
            } else
            if (L_OpenOrders == 3)
            {
               L_OrderLotSize = FixedLotsOrder4;
            } else
            if (L_OpenOrders == 4)
            {
               L_OrderLotSize = FixedLotsOrder5;
            } else
            if (L_OpenOrders == 5)
            {
               L_OrderLotSize = FixedLotsOrder6;
            } else
            if (L_OpenOrders == 6)
            {
               L_OrderLotSize = FixedLotsOrder7;
            } else
            if (L_OpenOrders == 7)
            {
               L_OrderLotSize = FixedLotsOrder8;
            } else
            if (L_OpenOrders == 8)
            {
               L_OrderLotSize = FixedLotsOrder9;
            } else
            if (L_OpenOrders > 8)
            {
               L_OrderLotSize = FixedLotsOrderLast;
            }
            if (UseDynamicLots)
            {
              L_OrderLotSize = G_OrderLotSize*L_OrderLotSize;
            }
            if (UseProgression)
            {
              L_OrderLotSize = L_ProgFactor*L_OrderLotSize;
            }
      L_OrderLotSize = NormalizeDouble(L_OrderLotSize,G_Decimals);
      if (L_OrderLotSize < G_MinLotSize)
      {
         Print("ERROR: Lot size "+L_OrderLotSize+" too small, min "+G_MinLotSize+" required");
         L_OrderLotSize = G_MinLotSize;
      }
      if (L_OrderLotSize > G_MaxLotSize)
      {
         Print("ERROR: Lot size "+L_OrderLotSize+" too big, max "+G_MaxLotSize+" allowed");
         L_OrderLotSize = G_MaxLotSize;
      }
	   if (L_OpenOrders<1)
	   {
	     L_Balance = AccountBalance();
	   }
	   int nextOrder = L_OpenOrders+1;
	   Print("Open buy @"+nextOrder+" at "+DoubleToStr(L_OrderLotSize,G_Decimals)+" at "+DoubleToStr(BuyPrice,4)+" sl "+DoubleToStr(L_sl,4)+" tp "+DoubleToStr(L_tp,4));
	   int ticket = OrderSend(Symbol(),OP_BUY,L_OrderLotSize,BuyPrice,L_Slippage,L_sl,L_tp,"Goblin BiPolar Buy",LongMagicNumber,0,Blue);
	   if (ticket < 0)
	   {
	     Print("ERROR opening buy order at "+BuyPrice);
	   }
	   return(0);   
    }   
   return(0);
  }


//====================================================== Begin Sell Order Processing SubRoutine =====================================================<<

void ShortGoblin()
  {   
   S_Profit=0;  
   S_OpenOrders=0;
   if (S_Balance <= 0)
   {
      S_Balance = AccountBalance();
   }
   if (L_PreviousOpenOrders < 1)
   {
     S_AccumulatedProfit = 0;
   }
   for(S_Count=0;S_Count<OrdersTotal();S_Count++)   
    {
     OrderSelect(S_Count, SELECT_BY_POS, MODE_TRADES);
	  if (OrderSymbol()==Symbol() && OrderMagicNumber() == ShortMagicNumber) {S_OpenOrders++;S_Profit=S_Profit+OrderProfit();}
    }     
      
   S_PipValue = MarketInfo(Symbol(),MODE_TICKVALUE);
   if (S_PipValue==0) { S_PipValue=5; }
   
   if (S_PreviousOpenOrders>S_OpenOrders) 
   {	  
	 for(S_Count=OrdersTotal();S_Count>=0;S_Count--)
	  {	     
      OrderSelect(S_Count, SELECT_BY_POS, MODE_TRADES);
	   if (OrderSymbol()==Symbol() && OrderMagicNumber() == ShortMagicNumber && OrderType() == OP_SELL) 
	    {
        int m_Ticket = OrderTicket();
	     OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),S_Slippage,Red); 
	     Print("Closing Sell Order ",m_Ticket);
	     return(0);
		 }
	  }
	  S_OldProfit = AccountBalance()-S_Balance-L_AccumulatedProfit;
	  if (L_AccumulatedProfit > 0)
	  {
	     Print("Subtracting accumulated buy profit "+L_AccumulatedProfit);
	  }
	  if (L_PreviousOpenOrders > 0)
	  {
	     S_AccumulatedProfit += S_OldProfit;
	  } else {
	     S_AccumulatedProfit = 0;
	  }
	  if (MaxProgStep > 12)
	  {
	    MaxProgStep = 12;
	  }
	  if (UseGlobalProg)
	  {
	    S_ProgStep = G_ProgStep;
	  }
	  if (S_OldProfit < LoserLimit*G_OrderLotSize)
	  {
	    // Loser
	    setWinner(S_PreviousOpenOrders,false,false,S_OldProfit);
	    S_ProgStep = 0;
	  } else {
	    // Winner
	    setWinner(S_PreviousOpenOrders,false,true,S_OldProfit);
	    S_ProgStep = S_ProgStep+1;
	    if (S_ProgStep > MaxProgStep)
	    {
	      S_ProgStep = MaxProgStep;
	      if (UseCycleProgSteps)
	      {
	        S_ProgStep = 0;
	      }
	    }
	  }
	  if (UseGlobalProg)
	  {
	    G_ProgStep = S_ProgStep;
	    L_ProgFactor = progSteps[G_ProgStep];
	  }
	  S_ProgFactor = progSteps[S_ProgStep];
	  if (S_ProgFactor <= 0)
	  {
	    S_ProgFactor = 1;
	  }
	  if (UseProgression)
	  {
	    if (S_OldProfit < LoserLimit*G_OrderLotSize)
	    {
	      Print("Last sell trade was a loser, factor is now "+S_ProgFactor+" (step "+S_ProgStep+")");
	    } else {
	      Print("Last sell trade was a winner, factor is now "+S_ProgFactor+" (step "+S_ProgStep+")");
	    }
	  }
	  LogStatistic();
   }

   S_PreviousOpenOrders=S_OpenOrders;
   if (S_OpenOrders>=ShortMaxTrades) 
    {
	  S_ContinueOpening=False;
    } else {
	  S_ContinueOpening=True;
    }

   if (S_LastPrice==0) 
    {
	  for(S_Count=0;S_Count<OrdersTotal();S_Count++)
      {	
       OrderSelect(S_Count, SELECT_BY_POS, MODE_TRADES);	
	    if (OrderSymbol()==Symbol() && OrderMagicNumber() == ShortMagicNumber && OrderType() == OP_SELL) 
		  {
	      S_LastPrice=OrderOpenPrice();
		   S_OrderType=1;
		  }
	   }
    }

   if (UseDynamicLots && !S_ContinueOpening)
   {
      G_OrderLotSize = StrToDouble(DoubleToStr(LotBaseSize*AccountEquity()/LotBaseEquity,G_Decimals));
   }
      
   if (S_OpenOrders<1){S_OrderType=OpenOrdersBasedOnTrendRSX();}
      

// Here comes the fun part we all waited for where we update those trailing stops....woohoo!!

   for(S_Count=OrdersTotal();S_Count>=0;S_Count--)
   {
    OrderSelect(S_Count, SELECT_BY_POS, MODE_TRADES);
    if (OrderSymbol() == Symbol() && OrderMagicNumber() == ShortMagicNumber && OrderType()==OP_SELL) 
	  {	
      if (ShortTrailingStop > 0 && (OrderOpenPrice()-Ask>=(ShortTrailingStop+ShortPips)*Point) && (OrderStopLoss()>(Ask+Point*ShortTrailingStop)) ) 
	    {					
	     OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*ShortTrailingStop,OrderClosePrice()-ShortTakeProfit*Point-ShortTrailingStop*Point,800,Purple);
	     return(0);	  					
		 }
     }
   }
   
   S_Profit=0;
   S_LastTicket=0;
   S_LastType=0;
	S_LastClosePrice=0;
	S_LastLots=0;	
   for(S_Count=0;S_Count<OrdersTotal();S_Count++)
    {
	  OrderSelect(S_Count, SELECT_BY_POS, MODE_TRADES);
	  if (OrderSymbol()==Symbol() && OrderMagicNumber() == ShortMagicNumber && OrderType()==OP_SELL) 
  	   {			
       S_LastTicket=OrderTicket();
	    S_LastType=OP_SELL;
 	    S_LastClosePrice=OrderClosePrice();
	    S_LastLots=OrderLots();
       S_Profit=S_Profit+OrderProfit();			 	   
      }
    }
   S_OldProfit = S_Profit;
    
   if (S_OpenOrders>=(ShortMaxTrades-ShortOrderstoProtect) && ShortAccountProtection==true) 
    {	    
     if (S_Profit>=ShortSecureProfit) 
      {
       OrderClose(S_LastTicket,S_LastLots,S_LastClosePrice,S_Slippage,Yellow);		 
       S_ContinueOpening=False;
       return(0);
      }
    }
       
   if (S_OpenOrders > 0 && S_OpenOrders < ShortMaxTrades && ((Bid-S_LastPrice)>=ShortPips*Point))
   {
      if (S_OrderType==1 && S_ContinueOpening)
      {
         //Print("Ready to open sell order at "+Bid);
      } else {
          Print("BLOCKED sell order at "+Bid);
     }
   }
      
    if (S_OrderType==1 && S_ContinueOpening && ((Bid-S_LastPrice)>=ShortPips*Point || S_OpenOrders<1)) 
     {		
      SellPrice=Bid;				
      S_LastPrice=0;
      if (ShortTakeProfit==0) { S_tp=0; }
       else { S_tp=SellPrice-ShortTakeProfit*Point; }	
      if (ShortInitialStop==0) { S_sl=0; }
       else { S_sl=NormalizeDouble(SellPrice+ShortInitialStop*Point + (ShortMaxTrades-S_OpenOrders)* ShortPips*Point, Digits);  }
        S_OrderLotSize=G_OrderLotSize;			
            if (S_OpenOrders <= 0)
            {
               S_OrderLotSize = FixedLotsOrder1;
            } else
            if (S_OpenOrders == 1)
            {
               S_OrderLotSize = FixedLotsOrder2;
            } else
            if (S_OpenOrders == 2)
            {
               S_OrderLotSize = FixedLotsOrder3;
            } else
            if (S_OpenOrders == 3)
            {
               S_OrderLotSize = FixedLotsOrder4;
            } else
            if (S_OpenOrders == 4)
            {
               S_OrderLotSize = FixedLotsOrder5;
            } else
            if (S_OpenOrders == 5)
            {
               S_OrderLotSize = FixedLotsOrder6;
            } else
            if (S_OpenOrders == 6)
            {
               S_OrderLotSize = FixedLotsOrder7;
            } else
            if (S_OpenOrders == 7)
            {
               S_OrderLotSize = FixedLotsOrder8;
            } else
            if (S_OpenOrders == 8)
            {
               S_OrderLotSize = FixedLotsOrder9;
            } else
            if (S_OpenOrders > 8)
            {
               S_OrderLotSize = FixedLotsOrderLast;
            }
            if (UseDynamicLots)
            {
              S_OrderLotSize = G_OrderLotSize*S_OrderLotSize;
            }
            if (UseProgression)
            {
              S_OrderLotSize = S_ProgFactor*S_OrderLotSize;
            }
       S_OrderLotSize = NormalizeDouble(S_OrderLotSize,G_Decimals);
       if (S_OrderLotSize < G_MinLotSize)
       {
         Print("ERROR: Lot size "+S_OrderLotSize+" too small, min "+G_MinLotSize+" required");
         S_OrderLotSize = G_MinLotSize;
       }
       if (S_OrderLotSize > G_MaxLotSize)
       {
         Print("ERROR: Lot size "+S_OrderLotSize+" too big, max "+G_MaxLotSize+" allowed");
         S_OrderLotSize = G_MaxLotSize;
       }
	    if (S_OpenOrders<1)
	    {
	      S_Balance = AccountBalance();
	    }
	    int nextOrder = S_OpenOrders+1;
	    Print("Open sell @"+nextOrder+" of "+DoubleToStr(S_OrderLotSize,G_Decimals)+" at "+DoubleToStr(SellPrice,4)+" sl "+DoubleToStr(S_sl,4)+" tp "+DoubleToStr(S_tp,4));
	    int ticket = OrderSend(Symbol(),OP_SELL,S_OrderLotSize,SellPrice,S_Slippage,S_sl,S_tp,"Goblin Bipolar Sell",ShortMagicNumber,0,Red);		    		    
	    if (ticket < 0)
	    {
	      Print("ERROR opening sell order at "+SellPrice);
	    }
	    return(0);    
     }      
    return(0);
  }  
  
int deinit()
  {
   return(0);
  }  
  

//==================================================== And here's the lovely Buy/Sell Signal Generator  ============================================<<

int OpenOrdersBasedOnTrendRSX()
{
     int SignalOrderType=3;
     double slowsma=0,mediumsma=0,fastsma=0;

// Let's check our very reliable super secret mega-signal...
 
   if (UseJMATrend)
   {
     double jma1=iCustom(Symbol(),Period(),"Turbo_JMA",JMAPeriod,-100,0,JMALag);
     double jma2=iCustom(Symbol(),Period(),"Turbo_JMA",JMAPeriod,-100,0,JMALag+1);
     if (MathAbs(jma1 - jma2) / Point > JMAPointDiff)
      {
       if (jma1 < jma2) {SignalOrderType=1;}
       if (jma1 > jma2) {SignalOrderType=2;}
      }
   }
   
// Welp, our mega-signal says no cigar...let's see what trusty 'ol RSX has to say...  
 
     if (SignalOrderType==3 && UseRSX)
     {
       double UpTrendVal = iCustom(Symbol(),Period(), "Turbo_JVEL",17,-100,0,1);
       double DnTrendVal = iCustom(Symbol(),Period(), "Turbo_JVEL",17,-100,1,1);
       double TrendVal = (UpTrendVal + DnTrendVal);
       double rsxcurr = iCustom(Symbol(),RSX_Timeframe,"Turbo_JRSX",RSX_Period,0,1);
       double rsxprev1 = iCustom(Symbol(),RSX_Timeframe,"Turbo_JRSX",RSX_Period,0,2);
       double rsxprev2 = iCustom(Symbol(),RSX_Timeframe,"Turbo_JRSX",RSX_Period,0,3);
       if (UseConservativeRSX_Signals==true)
        {            
         if (rsxcurr < rsxprev1 &&  rsxcurr < 70 && rsxprev1 > 70 && TrendVal < (-0.01)) {SignalOrderType=1;}    // we only go short on RSX downturns
         if (rsxcurr > rsxprev1 &&  rsxcurr > 30 && rsxprev1 < 30 && TrendVal > (0.01)) {SignalOrderType=2;}       // we only go long on RSX upturns
        }
       if (UseConservativeRSX_Signals==false)
        {            
         if (rsxcurr < rsxprev1 && TrendVal < (-0.01)) {SignalOrderType=1;}    // we only go short on RSX downturns
         if (rsxcurr > rsxprev1 && TrendVal > (0.01)) {SignalOrderType=2;}       // we only go long on RSX upturns
        }
     } 
      
     if (SignalOrderType == 1 &&  UseSMATrendFilter == true)
     {
        fastsma = iCustom(Symbol(),TrendFilterSMATimeFrame,"Turbo_JMA",TrendFilterFastSMAPeriod,-100,0,1);
        mediumsma = iCustom(Symbol(),TrendFilterSMATimeFrame,"Turbo_JMA",TrendFilterMediumSMAPeriod,-100,0,1);
        slowsma = iCustom(Symbol(),TrendFilterSMATimeFrame,"Turbo_JMA",TrendFilterSlowSMAPeriod,-100,0,1);
        if (slowsma > mediumsma && mediumsma > fastsma)
        {
           SignalOrderType = 1;
        } else {
           SignalOrderType = 3;
        } 
     }
     if (SignalOrderType == 2 &&  UseSMATrendFilter == true)
     {
        fastsma = iCustom(Symbol(),TrendFilterSMATimeFrame,"Turbo_JMA",TrendFilterFastSMAPeriod,-100,0,1);
        mediumsma = iCustom(Symbol(),TrendFilterSMATimeFrame,"Turbo_JMA",TrendFilterMediumSMAPeriod,-100,0,1);
        slowsma = iCustom(Symbol(),TrendFilterSMATimeFrame,"Turbo_JMA",TrendFilterSlowSMAPeriod,-100,0,1);
        if (slowsma < mediumsma && mediumsma < fastsma)
        {
           SignalOrderType = 2;
        } else {
           SignalOrderType = 3;
        } 
     }  
        
     return(SignalOrderType);
}


