|
//可以调整参数:EAType:决定是否单向开仓|起始手数0.02 or 0.05|加仓间距100 or 150|isSafeMode:向下取整 |
|
//1.同时开多单和空单的EA |
|
//2.程序可以初始化 |
|
//3.200点顺势平仓 |
|
//4.追踪止损 |
|
//5.处理跳空|Fix跳空bug |
|
//6.多空分开处理 |
|
//7.安全模式1.5倍时向下取整 |
|
//8.加上顺势加强逻辑震荡超过0.9手趋势初始仓位为0.05 |
|
//9.可以挂多个货币对 |
|
//10.跳空方法处理扛单问题——rollback无法解决问题 |
|
//11.加上了逻辑 |
|
//Modification: |
|
//1. only open one direction |
|
//2. close position when detect there is an 0.01 order opened in opposite direction |
|
|
|
int minTrailingStop=10; //初始化追踪止损点数 |
|
int maxTrailingStop=50; //最大追踪止损点数 |
|
int deltaPoint=10; //用来覆盖手续费 |
|
|
|
//Tuning Parameters EA调整是可以调整的参数 |
|
bool isAggressive=False; //when order number is illegal like 0.013, whether use math.floor or math.ceiling |
|
double initialisedOrderCount=0.02; //起始仓位大小 |
|
double orderIncreaseFactor=1.5; //加仓倍数 |
|
int increaseOrderDeltaStep=150; //间隔多少点加仓 |
|
int pointToCloseAntiTrendOrder=deltaPoint+increaseOrderDeltaStep/(orderIncreaseFactor-1);//多少点平掉震荡型仓位 |
|
int pointToCloseTrendOrder=200; //多少点平掉趋势型仓位 |
|
|
|
//Final Parameters |
|
double minOrderNumber=0.01;//The minimum order number allowed by platform |
|
int jumpUpFactor=3; |
|
int placeOrderDelta=5; |
|
double increaseTrendThreshold=0.9; |
|
int enlargedInitialisedOrderFactor=5; |
|
//EA Parameters |
|
bool isInitialised=False; |
|
int valueOfLastBuyOrder=0; |
|
int valueOfLastSellOrder=0; |
|
int currentAskValue=0; |
|
int currentBidValue=0; |
|
double numberOfLastBuyOrder=0.0; |
|
double numberOfLastSellOrder=0.0; |
|
ulong buyOrderIdArray[100];//Hold order ticket |
|
int buyOrderIdArrayIndex=0; |
|
ulong sellOrderIdArray[100]; |
|
int sellOrderIdArrayIndex=0; |
|
|
|
bool isAutoPlaceOrder=True; |
|
bool isBuyIsTrend=True; |
|
bool isSellIsTrend=True; |
|
int orderDirection=0; //1 means long and -1 means short 0 means both direction |
|
|
|
//+------------------------------------------------------------------+ |
|
//| | |
|
//+------------------------------------------------------------------+ |
|
void OnTick(void) |
|
{ |
|
//--- |
|
// initial data checks |
|
// it is important to make sure that the expert works with a normal |
|
// chart and the user did not make any mistakes setting external |
|
// variables (Lots, StopLoss, TakeProfit, |
|
// TrailingStop) in our case, we check TakeProfit |
|
// on a chart of less than 100 bars |
|
//--- |
|
if(Bars<100) |
|
{ |
|
Print("bars less than 100"); |
|
return; |
|
} |
|
|
|
if(!isInitialised) |
|
{ |
|
initialise(); |
|
} |
|
|
|
int cnt=OrdersTotal()-1; |
|
int totalBuyOrders=0; |
|
int totalSellOrders=0; |
|
isAutoPlaceOrder=True; |
|
for(;cnt>=0;cnt--) |
|
{ |
|
if(!OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES)) |
|
{ |
|
Print("Cannot select ",cnt+1," order!"); |
|
continue; |
|
} |
|
else |
|
{ |
|
if(OrderType()==OP_BUY&&OrderSymbol()==Symbol()) |
|
totalBuyOrders++; |
|
if(OrderType()==OP_SELL&&OrderSymbol()==Symbol()) |
|
totalSellOrders++; |
|
if((OrderType()==OP_BUYLIMIT||OrderType()==OP_SELLLIMIT)&&OrderSymbol()==Symbol()) |
|
{ |
|
isAutoPlaceOrder=False; |
|
Print("Order Type: ",OrderType()); |
|
Print("Close autoplace order"); |
|
} |
|
} |
|
} |
|
Print("Autoplace order",isAutoPlaceOrder); |
|
if(totalBuyOrders!=0) |
|
{ |
|
processor(OP_BUY); |
|
} |
|
if(totalSellOrders !=0) |
|
{ |
|
processor(OP_SELL); |
|
} |
|
if(totalBuyOrders==0&&isLongDirection()&&isAutoPlaceOrder) |
|
{ |
|
buyOrderIdArrayIndex=0; |
|
isBuyIsTrend=True; |
|
placeOrder(OP_BUY,initialisedOrderCount); |
|
} |
|
if(totalSellOrders==0&&isShortDirection()&&isAutoPlaceOrder) |
|
{ |
|
sellOrderIdArrayIndex=0; |
|
isSellIsTrend=True; |
|
placeOrder(OP_SELL,initialisedOrderCount); |
|
} |
|
|
|
} |
|
|
|
bool isLongDirection() |
|
{ |
|
if(orderDirection==1||orderDirection==0) |
|
return True; |
|
else |
|
return False; |
|
} |
|
|
|
bool isShortDirection() |
|
{ |
|
if(orderDirection==-1||orderDirection==0) |
|
return True; |
|
else |
|
return False; |
|
} |
|
|
|
double adjustOrderCount(double lots) |
|
{ |
|
double tmpLots=lots/minOrderNumber; |
|
if(isAggressive) |
|
return MathCeil(tmpLots)*minOrderNumber; |
|
else |
|
return MathFloor(tmpLots)*minOrderNumber; |
|
|
|
} |
|
|
|
void placeOrder(int orderType,double lots) |
|
{ |
|
double tmpLots=lots/minOrderNumber; |
|
lots=MathFloor(tmpLots)*minOrderNumber; |
|
int ticket; |
|
ticket=OrderSend(Symbol(),orderType,NormalizeDouble(lots,2),orderType==OP_BUY?Ask:Bid,3,0,0,"dl combine sample",16384,0,orderType==OP_BUY?Red:Green); |
|
if(ticket>0) |
|
{ |
|
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) |
|
{ |
|
if(orderType==OP_BUY) |
|
{ |
|
Print("Buy order opened : ",OrderOpenPrice()); |
|
valueOfLastBuyOrder=OrderOpenPrice()/Point(); |
|
numberOfLastBuyOrder=OrderLots(); |
|
buyOrderIdArray[buyOrderIdArrayIndex]=ticket; |
|
buyOrderIdArrayIndex++; |
|
} |
|
else if(orderType==OP_SELL) |
|
{ |
|
Print("Sell order opened : ",OrderOpenPrice()); |
|
valueOfLastSellOrder=OrderOpenPrice()/Point(); |
|
numberOfLastSellOrder=OrderLots(); |
|
sellOrderIdArray[sellOrderIdArrayIndex]=ticket; |
|
sellOrderIdArrayIndex++; |
|
} |
|
} |
|
else |
|
{ |
|
Print("Log: Cannot get the exist order!",Symbol()); |
|
return; |
|
} |
|
|
|
} |
|
|
|
|
|
} |
|
|
|
void processor(int orderType) |
|
{ |
|
double orderCount = initialisedOrderCount; |
|
int delta; |
|
currentAskValue=Ask/Point(); |
|
currentBidValue=Bid/Point(); |
|
|
|
if(orderType==OP_BUY) |
|
{ |
|
delta=currentAskValue-valueOfLastBuyOrder; |
|
|
|
if(isBuyIsTrend&&(currentBidValue-valueOfLastBuyOrder)>pointToCloseTrendOrder) |
|
{ |
|
closeAllOrders(buyOrderIdArray,OP_BUY); |
|
if(numberOfLastSellOrder>increaseTrendThreshold) |
|
{ |
|
orderCount=initialisedOrderCount*enlargedInitialisedOrderFactor; |
|
} |
|
|
|
placeOrder(OP_BUY,orderCount); |
|
} |
|
else if(delta<0&&MathAbs(delta)>increaseOrderDeltaStep&&MathAbs(delta)<increaseOrderDeltaStep+placeOrderDelta) |
|
{ |
|
placeOrder(OP_BUY,numberOfLastBuyOrder*orderIncreaseFactor); |
|
isBuyIsTrend=False; |
|
} |
|
else if(delta<0&&MathAbs(delta)>increaseOrderDeltaStep*jumpUpFactor) |
|
{ |
|
double jumpGap=MathAbs(delta); |
|
double tmpOrderIncreaseFactor=orderIncreaseFactor; |
|
while(jumpGap/(double)increaseOrderDeltaStep>=1) |
|
{ |
|
tmpOrderIncreaseFactor+=orderIncreaseFactor; |
|
jumpGap=jumpGap-increaseOrderDeltaStep; |
|
} |
|
placeOrder(OP_BUY,numberOfLastBuyOrder*tmpOrderIncreaseFactor); |
|
isBuyIsTrend=False; |
|
} |
|
if(!isBuyIsTrend&&(Bid/Point()-valueOfLastBuyOrder>pointToCloseAntiTrendOrder+minTrailingStop)) |
|
{ |
|
int tmpTrailingStop=MathMax((Bid/Point()-valueOfLastBuyOrder-pointToCloseAntiTrendOrder),minTrailingStop); |
|
tmpTrailingStop=MathMin(tmpTrailingStop,maxTrailingStop); |
|
modifyAllOrders(buyOrderIdArray,OP_BUY,tmpTrailingStop); |
|
} |
|
|
|
} |
|
else if(orderType==OP_SELL) |
|
{ |
|
delta=currentBidValue-valueOfLastSellOrder; |
|
if(isSellIsTrend&&(valueOfLastSellOrder-currentAskValue)>pointToCloseTrendOrder) |
|
{ |
|
closeAllOrders(sellOrderIdArray,OP_SELL); |
|
if(numberOfLastBuyOrder>increaseTrendThreshold) |
|
{ |
|
orderCount=initialisedOrderCount*enlargedInitialisedOrderFactor; |
|
} |
|
|
|
placeOrder(OP_SELL,orderCount); |
|
} |
|
else if(delta>increaseOrderDeltaStep&&delta<increaseOrderDeltaStep+placeOrderDelta) |
|
{ |
|
placeOrder(OP_SELL,numberOfLastSellOrder*orderIncreaseFactor); |
|
isSellIsTrend=False; |
|
} |
|
else if(delta>increaseOrderDeltaStep*jumpUpFactor) |
|
{ |
|
jumpGap=MathAbs(delta); |
|
tmpOrderIncreaseFactor=orderIncreaseFactor; |
|
while(jumpGap/increaseOrderDeltaStep>1) |
|
{ |
|
tmpOrderIncreaseFactor+=orderIncreaseFactor; |
|
jumpGap=jumpGap-increaseOrderDeltaStep; |
|
} |
|
placeOrder(OP_SELL,numberOfLastSellOrder*tmpOrderIncreaseFactor); |
|
isSellIsTrend=False; |
|
} |
|
if(!isSellIsTrend&&(valueOfLastSellOrder-Ask/Point()>pointToCloseAntiTrendOrder+minTrailingStop)) |
|
{ |
|
tmpTrailingStop=MathMax((valueOfLastSellOrder-Ask/Point()-pointToCloseAntiTrendOrder),minTrailingStop); |
|
tmpTrailingStop=MathMin(tmpTrailingStop,maxTrailingStop); |
|
modifyAllOrders(sellOrderIdArray,OP_SELL,tmpTrailingStop); |
|
} |
|
|
|
} |
|
} |
|
|
|
void closeAllOrders(ulong &orderIdArray[],int orderType) |
|
{ |
|
int cnt; |
|
int index=(orderType==OP_BUY)?buyOrderIdArrayIndex:sellOrderIdArrayIndex; |
|
for(cnt=0;cnt<index;cnt++) |
|
{ |
|
ulong orderId=orderIdArray[cnt]; |
|
if(!OrderSelect(orderId,SELECT_BY_TICKET,MODE_TRADES)) |
|
{ |
|
Print("Cannot select ",orderId," order!"); |
|
continue; |
|
} |
|
else |
|
{ |
|
if(OrderType()==OP_BUY) |
|
if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet)) |
|
Print("OrderClose error ",GetLastError()); |
|
if(OrderType()==OP_SELL) |
|
if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet)) |
|
Print("OrderClose error ",GetLastError()); |
|
} |
|
} |
|
if(orderType==OP_BUY) |
|
{ |
|
buyOrderIdArrayIndex=0; |
|
} |
|
else if(orderType==OP_SELL) |
|
{ |
|
sellOrderIdArrayIndex=0; |
|
} |
|
|
|
} |
|
|
|
void modifyAllOrders(ulong &orderIdArray[],int orderType,int tmpTrailingStop) |
|
{ |
|
int cnt; |
|
int index=(orderType==OP_BUY)?buyOrderIdArrayIndex:sellOrderIdArrayIndex; |
|
for(cnt=0;cnt<index;cnt++) |
|
{ |
|
ulong orderId=orderIdArray[cnt]; |
|
if(!OrderSelect(orderId,SELECT_BY_TICKET,MODE_TRADES)) |
|
{ |
|
Print("Cannot select ",orderId," order!"); |
|
continue; |
|
} |
|
else |
|
{ |
|
if(OrderType()==OP_BUY) |
|
if(OrderStopLoss()<Bid-Point*tmpTrailingStop) |
|
{ |
|
if(!OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*tmpTrailingStop,OrderTakeProfit(),0,Red)) |
|
Print("OrderModify error ",GetLastError()); |
|
} |
|
if(OrderType()==OP_SELL) |
|
if((OrderStopLoss()>(Ask+Point*tmpTrailingStop))|| (OrderStopLoss()==0)) |
|
{ |
|
if(!OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*tmpTrailingStop,OrderTakeProfit(),0,Green)) |
|
Print("OrderModify error ",GetLastError()); |
|
} |
|
} |
|
} |
|
|
|
} |
|
|
|
void initialise() |
|
{ |
|
int cnt=OrdersTotal()-1; |
|
for(;cnt>=0;cnt--) |
|
{ |
|
if(!OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES)) |
|
{ |
|
Print("Cannot select ",cnt+1," order!"); |
|
continue; |
|
} |
|
else |
|
{ |
|
if(OrderType()==OP_BUY && OrderSymbol()==Symbol()) |
|
{ |
|
double buyOrderLots=OrderLots(); |
|
if(buyOrderLots>numberOfLastBuyOrder) |
|
{ |
|
numberOfLastBuyOrder=buyOrderLots; |
|
valueOfLastBuyOrder=OrderOpenPrice()/Point(); |
|
} |
|
buyOrderIdArray[buyOrderIdArrayIndex]=OrderTicket(); |
|
buyOrderIdArrayIndex++; |
|
} |
|
if(OrderType()==OP_SELL && OrderSymbol()==Symbol()) |
|
{ |
|
double sellOrderLots=OrderLots(); |
|
if(sellOrderLots>numberOfLastSellOrder) |
|
{ |
|
numberOfLastSellOrder=sellOrderLots; |
|
valueOfLastSellOrder=OrderOpenPrice()/Point(); |
|
} |
|
sellOrderIdArray[sellOrderIdArrayIndex]=OrderTicket(); |
|
sellOrderIdArrayIndex++; |
|
} |
|
} |
|
} |
|
if(buyOrderIdArrayIndex>2) |
|
{ |
|
isBuyIsTrend=False; |
|
} |
|
if(sellOrderIdArrayIndex>2) |
|
{ |
|
isSellIsTrend=False; |
|
} |
|
isInitialised=True; |
|
} |