在某些交易策略中,您可能需要针对同一个入场信号(或持仓)下达多个订单,这些订单可以拥有各自不同的止损、止盈水平以及手数大小。实现这一需求有多种途径,最直接的一种方法是,发出的每一笔订单都单独编写一条 OrderSend()
指令。这种方式的前提是,您每次交易时发出的订单数量是固定不变的。
另一种更为灵活的方法是利用 for
循环结构来批量发送订单。这种方式允许您根据需要动态调整单次发出的订单数量。您可以预先将每笔订单的止损和止盈价位存储在数组中,然后在 for
循环内部依次读取并使用这些预设值。
让我们以一个实例来说明:首先,为前三笔订单定义各自的止损点数和止盈点数(以外部变量的形式)。如果策略需要发出超过三笔的订单,那么多出的订单将不会被自动设置止损或止盈。同时,我们再增加一个外部变量,用以控制本次交易总共需要发出的订单数量。
extern int StopLoss1 = 20; // 第1单止损点数
extern int StopLoss2 = 40; // 第2单止损点数
extern int StopLoss3 = 60; // 第3单止损点数
extern int TakeProfit1 = 40; // 第1单止盈点数
extern int TakeProfit2 = 80; // 第2单止盈点数
extern int TakeProfit3 = 120;// 第3单止盈点数
extern int MaxOrders = 3; // 本次交易计划发出的订单总数
接下来,我们需要声明用于存储具体止损、止盈价位的数组,然后计算出这些价位,并将它们填充到相应的数组元素中:
double BuyTakeProfit[3]; // 存储买单止盈价位的数组
double BuyStopLoss[3]; // 存储买单止损价位的数组
// 假设 CalcBuyTakeProfit 和 CalcBuyStopLoss 是先前已定义的函数
// 它们根据基准价 (如Ask) 和点数计算出具体的止盈/止损价格
BuyTakeProfit[0] = CalcBuyTakeProfit(Symbol(), TakeProfit1, Ask);
BuyTakeProfit[1] = CalcBuyTakeProfit(Symbol(), TakeProfit2, Ask);
BuyTakeProfit[2] = CalcBuyTakeProfit(Symbol(), TakeProfit3, Ask);
BuyStopLoss[0] = CalcBuyStopLoss(Symbol(), StopLoss1, Ask);
BuyStopLoss[1] = CalcBuyStopLoss(Symbol(), StopLoss2, Ask);
BuyStopLoss[2] = CalcBuyStopLoss(Symbol(), StopLoss3, Ask);
代码首先声明了两个数组:BuyTakeProfit
和 BuyStopLoss
,分别用于存放计算后的止盈和止损价格。在声明数组时,必须明确指定其包含的元素数量。数组的索引(下标)是从0开始计数的,因此,当我们声明一个大小为3的数组时,其有效的索引范围是0、1和2。
随后,我们调用CalcBuyStopLoss()
和 CalcBuyTakeProfit()
函数,来计算具体的止损和止盈价格。计算结果被分别赋给对应数组的元素。请再次留意,数组的第一个元素的索引是0,第三个元素的索引是2。
以下是用于批量发送这些订单的 for
循环结构:
for(int Count = 0; Count < MaxOrders; Count++) // Count 从0到 MaxOrders-1
{
int OrdInt = Count + 1; // 用于订单注释的序号 (1, 2, 3...)
OrderSend(Symbol(), OP_BUY, LotSize, Ask, UseSlippage,
BuyStopLoss[Count], BuyTakeProfit[Count], // 从数组中取对应的SL/TP
"Buy Order " + (string)OrdInt, // 订单注释,如 "Buy Order 1"
MagicNumber, 0, Green);
}
循环变量 Count
从0开始,正好对应数组的第一个元素。循环执行的总次数(即发出的订单总数)由 MaxOrders
的值决定(循环条件 Count < MaxOrders
或 Count <= MaxOrders - 1
)。在循环的每一次迭代中,程序会使用当前的 Count
值作为索引,从 BuyStopLoss
和 BuyTakeProfit
数组中取出相应的止损和止盈价格。
我们还引入了一个 OrdInt
变量,它的值等于 Count + 1
,目的是为了在订单注释中生成一个从1开始的序号(例如,”Buy Order 1″, “Buy Order 2” 等)。最后,OrderSend()
函数根据这些参数(包括从数组中获取的止损和止盈价位)发送订单。
这仅仅是处理多订单下单的一种实现方式,尽管它在预设止损止盈方面可能较为高效。其主要局限在于,我们只能为数量有限(由数组大小决定)的订单预先计算和设定止损止盈。作为一种替代方案,我们可以采用按比例递增的方式来设定止损和止盈值,从而支持发送理论上无限数量的订单:
extern int StopLossStart = 20; // 初始订单的止损点数
extern int StopLossIncr = 20; // 每增加一个订单,止损增加的点数
extern int TakeProfitStart = 40; // 初始订单的止盈点数
extern int TakeProfitIncr = 40; // 每增加一个订单,止盈增加的点数
extern int MaxOrders = 5; // 本次交易计划发出的订单总数
在上述设定中,第一笔订单的止损将是20点。此后每增加一笔订单,其止损将在前一笔的基础上再增加20点。止盈的设置与此类似,第一笔订单的止盈为40点,后续订单的止盈依次增加40点。采用这种方法时,我们不再需要预先填充数组,而是在 for
循环内部动态计算每笔订单的止损和止盈:
for(int Count = 0; Count < MaxOrders; Count++) // Count 从0到 MaxOrders-1
{
int OrdInt = Count + 1; // 订单注释序号
// 计算当前订单的止损点数
int UseStopLoss = StopLossStart + (StopLossIncr * Count);
// 计算当前订单的止盈点数
int UseTakeProfit = TakeProfitStart + (TakeProfitIncr * Count);
// 将点数转换为实际价格 (假设 CalcBuyStopLoss 和 CalcBuyTakeProfit 已定义)
double ActualBuyStopLoss = CalcBuyStopLoss(Symbol(), UseStopLoss, Ask);
double ActualBuyTakeProfit = CalcBuyTakeProfit(Symbol(), UseTakeProfit, Ask);
OrderSend(Symbol(), OP_BUY, LotSize, Ask, UseSlippage,
ActualBuyStopLoss, ActualBuyTakeProfit,
"Buy Order " + (string)OrdInt, MagicNumber, 0, Green);
}
我们通过公式 起始值 + (增量 * 循环次数)
来确定每笔订单的止盈和止损点数。具体来说,止损点数是 StopLossStart + (StopLossIncr * Count)
,止盈点数是 TakeProfitStart + (TakeProfitIncr * Count)
。对于第一笔订单(此时 Count
为0),其止损/止盈点数就等于设定的 StopLossStart
或 TakeProfitStart
。
计算出点数后,我们再调用第4章中定义的函数,将这些点数转换成具体的止损和止盈价格。最后,使用 OrderSend()
函数发送订单。循环将持续执行,直到成功发送了 MaxOrders
所指定数量的订单。这种方法的优势在于,我们可以通过 MaxOrders
变量灵活设定希望发出的订单数量,并确保每一笔发出的订单都带有动态计算的止损和止盈。