//+------------------------------------------------------------------+
//| FGProBot 0.9.5 ゥ pip.digger 2013.02.22 |
//| |
//| |
//+------------------------------------------------------------------+
#property copyright "FGProBot 0.9.5 ゥ pip.digger 2013.02.22"
#property link "WwI.org"
// externals
extern string EA_Configuration = "==== EA Configuration ====";
extern int Magic = 20130130;
extern string BotComment = "0.9.5";
extern string TradeSettings = "==== Trade settings ====";
extern int Slippage = 3;
extern string TimeSettings = "==== Time settings ====";
extern int MondayStartHour = 11;
extern int FridayStopHour = 18;
extern string OpenSettings = "==== Open trade settings ====";
extern int FastVolatilityBase = 10;
extern int SlowVolatilityBase = 50;
extern int SlowVolatilityOffset = 4;
extern double VolatilityFactor = 1.5;
extern bool OpenWithTrendOnly = false;
extern string CloseSettings = "==== Close trade settings ====";
extern double StopLoss = 0.23;
extern double RiskRewardRatio = 2.1;
extern int RangeMode = 2;
extern int RangeMaxBase = 16;
extern int RangeMinBase = 10;
extern bool NormalizeRange = true;
extern bool MoveTPSL = true;
extern bool UseProfitLock = true;
extern double ProfitLockTrigger = 0.85;
extern double ProfitLockPercent = 0.8;
extern bool UseVolaClose = true;
extern double VolaCloseTrigger = 0.7;
extern double VolaCloseMinProfit = 0.3;
bool UseTrailingStop = false;
double TrailingStopTrigger = 0.5;
int ATRBase = 7;
double ATRFactor = 6;
extern string Money_Management = "==== Money Management ====";
extern double LotSize = 0.1;
extern double Risk = 1.0;
extern bool RiskBooster = true;
extern double BoosterPower = 0.8;
extern double BoosterCap = 5.0;
// globals
double MinLot, MaxLot, LotDigits, StpLvl, Range;
datetime bt = 0;
int lm = -1, ld = -1;
string symb, txt = "\n FGProBot 0.9.5 ゥ pip.digger \n Lot: ";
int init()
{
symb = Symbol();
if(Digits%2==1) Slippage *= 10;
LotDigits = MathLog(MarketInfo(symb, MODE_LOTSTEP)) / MathLog(0.1);
MinLot = MarketInfo(symb, MODE_MINLOT);
MaxLot = MarketInfo(symb, MODE_MAXLOT);
StpLvl = MarketInfo(symb, MODE_STOPLEVEL);
}
int start()
{
double VolFac, x = 1.0, Dist;
int i;
static int ticket;
string OrderCmt;
// run every new bar openening
if(bt != Time[0]) {
bt = Time[0];
VolFac = VF(FastVolatilityBase, SlowVolatilityBase);
switch(RangeMode) {
case 1:
Range = High[iHighest(NULL, 0, MODE_HIGH, RangeMaxBase, 1)] - Low[iLowest(NULL, 0, MODE_LOW, RangeMaxBase, 1)];
break;
case 2:
double avg = 0.0, avgt;
for(i = 1; i <= RangeMinBase; i++)
avg += High[i] - Low[i];
avg /= RangeMinBase;
for(i = RangeMinBase + 1; i <= RangeMaxBase; i++) {
avgt = (avg * (i - 1) + (High[i] - Low[i])) / i;
if(avgt > avg)
break;
else
avg = avgt;
}
i--;
Range = High[iHighest(NULL, 0, MODE_HIGH, i, 1)] - Low[iLowest(NULL, 0, MODE_LOW, i, 1)];
break;
case 3:
if(ld != Day()) { // calc once per new day
ld = Day();
double a[100];
int k = MathCeil(RangeMaxBase * 0.4);
Range = 0.0;
for(i = 0; i < RangeMaxBase; i++)
a[i] = iHigh(NULL, PERIOD_D1, i + 1) - iLow(NULL, PERIOD_D1, i + 1);
ArraySort(a, RangeMaxBase, 0, MODE_DESCEND);
for(i = 0; i < k; i++)
Range += a[i];
Range /= k;
}
break;
} // end switch RangeMode
if(NormalizeRange) {
for(i = OrdersTotal() - 1; i >= 0; i--) {
if(OrderSelect(i, SELECT_BY_POS))
if(OrderSymbol() == symb && OrderMagicNumber() == Magic) {
if(VolFac * VolFacFromComment() < 0.0) // if VF now and VF from date have different sign -> skip
continue;
Range = MathMin(Range / MathAbs(VolFac), RangeFromComment() / MathAbs(VolFacFromComment())) * MathAbs(VolFac);
}
}
} // end if NormalizeRange
// do something with opened trades on every new bar opening
if(MoveTPSL) {
for(i = OrdersTotal() - 1; i >= 0; i--)
if(OrderSelect(i, SELECT_BY_POS))
if(OrderSymbol() == symb && OrderMagicNumber() == Magic) {
double vfr = VolFac / VolFacFromComment();
if(vfr < 0.0) // if VF now and VF from date have different sign -> skip
continue;
switch(OrderType()) {
case OP_BUY:
if(vfr > 1.0) {
Dist = RangeFromComment() * StopLoss;
if(Ask + Dist * RiskRewardRatio > OrderTakeProfit())
OrderModify(OrderTicket(), OrderOpenPrice(), ND(Bid - Dist), ND(Ask + Dist * RiskRewardRatio), 0, Blue);
}
break;
case OP_SELL:
if(vfr > 1.0) {
Dist = RangeFromComment() * StopLoss;
if(Bid - Dist * RiskRewardRatio < OrderTakeProfit())
OrderModify(OrderTicket(), OrderOpenPrice(), ND(Ask + Dist), ND(Bid - Dist * RiskRewardRatio), 0, Red);
}
break;
} // end switch
} // end symbol and magic check
} // end MoveTPSL
if(UseVolaClose) // Close open trades if Vola falls below VolaCloseTrigger * VolatilityFactor
if(VolFac / VolatilityFactor < VolaCloseTrigger)
for(i = OrdersTotal() - 1; i >= 0; i--)
if(OrderSelect(i, SELECT_BY_POS))
if(OrderSymbol() == symb && OrderMagicNumber() == Magic)
switch(OrderType()) {
case OP_BUY:
if(Bid > OrderOpenPrice() + (OrderTakeProfit() - OrderOpenPrice()) * VolaCloseMinProfit)
OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, Blue);
break;
case OP_SELL:
if(Ask < OrderOpenPrice() - (OrderOpenPrice() - OrderTakeProfit()) * VolaCloseMinProfit)
OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, Red);
break;
} // end switch
Comment(txt, Lot());
} // end run every new bar openening
// place new trade if prerequisites are met
if(IsTradeTime() && MathAbs(VolFac) > VolatilityFactor && !(OpenWithTrendOnly && (CheckOpenWithTrend() * VolFac > 0.0))) {
OrderCmt = StringConcatenate("vf[", DoubleToStr(VolFac, 2), "] rg[", DoubleToStr(Range/Point, 0), "] ", BotComment);
if(RiskBooster) {
x = MathPow(MathAbs(VolFac) / VolatilityFactor, BoosterPower);
if(BoosterCap > 1.0)
x = MathMin(x, BoosterCap);
}
if(VolFac > VolatilityFactor) {
ticket = OrderSend(symb, OP_BUY, Lot(x), Ask, Slippage, 0.0, 0.0, OrderCmt, Magic, 0, Blue);
if(ticket != -1)
VolFac = 0.0;
} else if(VolFac < (-VolatilityFactor)) {
ticket = OrderSend(symb, OP_SELL, Lot(x), Bid, Slippage, 0.0, 0.0, OrderCmt, Magic, 0, Red);
if(ticket != -1)
VolFac = 0.0;
}
}
// set hard TP & SL for last opened trade
if(OrderSelect(ticket, SELECT_BY_TICKET))
if(OrderSymbol() == symb && OrderMagicNumber() == Magic)
switch(OrderType()) {
case OP_BUY:
if(OrderModify(ticket, OrderOpenPrice(), ND(Bid - MathMax(Range * StopLoss, StpLvl * Point)), ND(Ask + Range * StopLoss * RiskRewardRatio), 0, Blue))
ticket = -1;
break;
case OP_SELL:
if(OrderModify(ticket, OrderOpenPrice(), ND(Ask + MathMax(Range * StopLoss, StpLvl * Point)), ND(Bid - Range * StopLoss * RiskRewardRatio), 0, Red))
ticket = -1;
break;
default:
ticket = -1;
}
// run every minute
if(lm != Minute()) {
lm = Minute();
if(UseProfitLock) { // set SL to ProfitLockPercent * PriceDelta, when ProfitLockTrigger / TP has been reached
for(i = OrdersTotal() - 1; i >= 0; i--)
if(OrderSelect(i, SELECT_BY_POS))
if(OrderSymbol() == symb && OrderMagicNumber() == Magic)
switch(OrderType()) {
case OP_BUY:
Dist = OrderTakeProfit() - OrderOpenPrice();
x = (OrderStopLoss() - OrderOpenPrice()) / Dist;
Dist *= ProfitLockTrigger;
if(x < ProfitLockTrigger * ProfitLockPercent && Bid > OrderOpenPrice() + Dist)
OrderModify(OrderTicket(), OrderOpenPrice(), ND(OrderOpenPrice() + Dist * ProfitLockPercent), OrderTakeProfit(), 0, Blue);
break;
case OP_SELL:
Dist = OrderOpenPrice() - OrderTakeProfit();
x = (OrderOpenPrice() - OrderStopLoss()) / Dist;
Dist *= ProfitLockTrigger;
if(x < ProfitLockTrigger * ProfitLockPercent && Ask < OrderOpenPrice() - Dist)
OrderModify(OrderTicket(), OrderOpenPrice(), ND(OrderOpenPrice() - Dist * ProfitLockPercent), OrderTakeProfit(), 0, Red);
break;
} // end switch
} // end UseProfitLock
if(UseTrailingStop) { // Trail with ATR based SL, when TrailingStopTrigger / TP has been reached
Dist = ATRFactor * iATR(NULL, 0, ATRBase, 0);
for(i = OrdersTotal() - 1; i >= 0; i--)
if(OrderSelect(i, SELECT_BY_POS))
if(OrderSymbol() == symb && OrderMagicNumber() == Magic)
switch(OrderType()) {
case OP_BUY:
if((Bid - OrderOpenPrice()) / (OrderTakeProfit() - OrderOpenPrice()) > TrailingStopTrigger)
if(Bid - OrderStopLoss() > Dist)
OrderModify(OrderTicket(), OrderOpenPrice(), ND(Bid - Dist), OrderTakeProfit(), 0, Blue);
break;
case OP_SELL:
if((OrderOpenPrice() - Ask) / (OrderOpenPrice() - OrderTakeProfit()) > TrailingStopTrigger)
if(OrderStopLoss() - Ask > Dist)
OrderModify(OrderTicket(), OrderOpenPrice(), ND(Ask + Dist), OrderTakeProfit(), 0, Red);
break;
} // end switch
} // end UseTrailingStop
} // end run every minute
return(0);
}
// return lotsize for next trade
double Lot(double x = 1.0)
{
if(Risk > 0.0)
x *= AccountFreeMargin() * (Risk/100.0) / ((Range * StopLoss / Point) * MarketInfo(symb, MODE_TICKVALUE));
else
x = LotSize;
return(NormalizeDouble(MathMin(MathMax(MinLot, x), MaxLot), LotDigits));
}
// normalize double to accuracy of Digits of current symbol price
double ND(double val)
{
return (NormalizeDouble(val, Digits));
}
// calculate volatility (acceleration) factor
double VF(int Fa, int Sa)
{
int i;
double sumF = 0.0, sumS = 0.0, k;
for (i = 1; i <= Sa; i++)
sumS += MathAbs(Close[i + SlowVolatilityOffset] - Open[i + SlowVolatilityOffset]);
sumS /= Sa;
k = 2.0 / (Fa + 1.0);
for (i = 1; i <= Fa; i++)
sumF += MathPow((1.0 - k), (i - 1)) * (Close[i] - Open[i]);
sumF *= k;
return(sumF/sumS);
}
// trading time filter
bool IsTradeTime()
{
if(MondayStartHour >= 0)
if(DayOfWeek() == 0 || DayOfWeek() == 1 && Hour() < MondayStartHour)
return(false);
if(FridayStopHour >= 0)
if(DayOfWeek() == 6 || DayOfWeek() == 5 && Hour() >= FridayStopHour)
return(false);
return(true);
}
// extract range from trade comment
double RangeFromComment()
{
int start, length;
start = StringFind(OrderComment(), "rg[") + 3;
length = StringFind(OrderComment(), "]", start) - start;
return(StrToDouble(StringSubstr(OrderComment(), start, length)) * Point);
}
// extract volfac from trade comment
double VolFacFromComment()
{
int start, length;
start = StringFind(OrderComment(), "vf[") + 3;
length = StringFind(OrderComment(), "]", start) - start;
return(StrToDouble(StringSubstr(OrderComment(), start, length)));
}
// check price relative to open orders, return values:
// -1 : do not place new sell order!
// 0 : new buy or sell oder OK
// 1 : do not place new buy order!
int CheckOpenWithTrend(double PrcDelta = 0.0)
{
bool IsBelowLowest = true, IsAboveHighest = true, ExistSellOrder = false, ExistBuyOrder = false;
for(int i = OrdersTotal() - 1; i >= 0; i--)
if(OrderSelect(i, SELECT_BY_POS))
if(OrderSymbol() == symb && OrderMagicNumber() == Magic)
switch(OrderType()) {
case OP_BUY:
ExistBuyOrder = true;
if(Ask <= OrderOpenPrice() + PrcDelta)
IsAboveHighest = false;
break;
case OP_SELL:
ExistSellOrder = true;
if(Bid >= OrderOpenPrice() + PrcDelta)
IsBelowLowest = false;
break;
}
if(ExistSellOrder && !IsBelowLowest)
return(-1);
else if (ExistBuyOrder && !IsAboveHighest)
return(1);
else
return(0);
}