A_SendOrderEx函数下单为什么每次都会连续下单2次呢
不管是开仓还是平仓,明明代码只执行一次,为啥总是会连续发出2次委托单呢,完整代码如下:
//------------------------------------------------------------------------
// 简称: ThreeRedSoldiersDay
// 名称: 红三兵日内
// 类别: 公式应用
// 类型: 用户应用
// 输出: Void
// 主要基于红三兵思路。一分钟k线连续2根低点抬高即在第三根k线运行时以限定价格买入开仓。
Params
Numeric Start(10); //开盘10分钟开始
Numeric Add(3); //高低点加减几跳入场
Numeric Exit(7); //开仓后第几根离场
Numeric EtSecond(50); //出场秒数(不能大于59)
Numeric EndT(0.1458); //收盘前平仓时间
Numeric Loss(3); //止损跳数
String Period(\"1m\"); //参考周期
String AccountID(\"\"); //绑定交易账户,只支持单个账户,如tbf_myAct01
Numeric Lots(1); //开仓手数
Numeric Recall(0); //是否回溯
Vars
Global Integer IsSubs; //是否加载多周期K线标记
Series<String> Contract; //获取合约代码
Series<String> myContract; //获取交易合约代码
Bool condLong; //多头开仓条件
Bool condShort; //空头开仓条件
Series<Numeric> MinPoint; //一跳
Series<Numeric> LossPrice; //止损价格
Series<Numeric> myPrice; //操作价格
Series<Numeric> IsNewBar; //是否新的大周期Bar
Global Numeric MPL; //多头开仓状态
Global Numeric MPS; //空头开仓状态
Global Numeric BS; //开仓后Bar数
Global Integer OrderID; //报单号
Defs
//此处添加公式函数
Events
//此处实现事件函数
//初始化事件函数,策略运行期间,首先运行且只有一次
OnInit()
{
//绑定交易账户
Array<String> Acc;
StringSplit(AccountID,\",\",Acc);
Integer i;
For i = 0 To GetArraySize(Acc) - 1
{
A_BindTradeAccount(Acc[i]);
Print(\"公式初始化\"+\":绑定交易账户:\"+Acc[i]);
//Break;
}
}
OnBarOpen(ArrayRef<Integer> indexs)
{
Range[1:1]
{
BS=BS+1;
}
}
//Bar更新事件函数,参数indexs表示变化的数据源图层ID数组
OnBar(ArrayRef<Integer> indexs)
{
//初始化跨周期K线数据
If (CurrentBar==0 And IsSubs==0)
{
//获取合约名称
Contract=Symbol();
Print(\"Contract:\"+Contract);
//订阅K线数据
SubscribeBar(Contract,Period,BeginDateTime, 0, Enum_Data_FullPeriod);
IsSubs=1;
}
//获取交易合约
If (myContract==\"\")
{
If (RelativeSymbol()==\"\")
{
myContract=Symbol();
}Else
{
myContract=RelativeSymbol();
}
}
Commentary(\"当前交易合约:\"+myContract);
MinPoint=MinMove()*PriceScale();
Commentary(\"该品种1跳等于\"+Text(MinPoint)+\"点\");
//重置大周期新的Bar标记
If (Time==Data1.Time)
{
IsNewBar=0;
}
Commentary(\"Second:\"+Text(Second));
//收盘前平仓
//CloseMinutes
If (BS>=0 And (MPL==1 Or MPS==1) And (Time>=EndT And Time<=0.15))
{
//多头离场
If (Recall==1)
{
//支持回溯
If (MarketPosition==1 And Vol>0)
{
myPrice=Open;
Sell(Lots,myPrice);
MPL=0;
MPS=0;
Commentary(\"收盘前平仓\");
}
If (MarketPosition==-1 And Vol>0)
{
myPrice=Open;
BuyToCover(Lots,myPrice);
MPL=0;
MPS=0;
Commentary(\"收盘前平仓\");
}
}Else
{
//不支持回溯
Position pos;
Bool ret = A_GetPosition(myContract, pos, \"\", 0);
//Commentary(\"A_GetPosition:\" + IIFString(ret, \"True\", \"False\") + \",\" + Text(pos));
If (ret)
{
Commentary(\"多头可平仓:\"+Text(pos.longCanSellVolume));
Commentary(\"空头可平仓:\"+Text(pos.shortCanCoverVolume));
MPL=Max(pos.longCanSellVolume,1);
MPS=Max(pos.shortCanCoverVolume,1);
//If (MPL==1 And BarStatus==2) Print(Text(Time())+\":MPL=\"+Text(MPL));
//If (MPS==1 And BarStatus==2) Print(Text(Time())+\":MPS=\"+Text(MPS));
Array<Integer> orderIds; //委托ID
//Print(\"A_BrokerID:\"+Text(A_BrokerID()));
If (MPL==1 And Vol>0 And BarStatus==2)
{
A_SendOrderEx(myContract,Enum_Sell,Enum_ExitToday,Lots,Q_BidPrice() ,orderIds,\"\",\"\",A_AccountIndex(A_AccountID(),A_BrokerID()));
OrderID=orderIds[0];
Commentary(\"多头止损:\"+Text(Lots)+\"手\");
Print(Text(Time())+\":多头止损:\"+Text(Lots)+\"手\");
}
If (MPS==1 And Vol>0 And BarStatus==2)
{
A_SendOrderEx(myContract,Enum_Buy,Enum_ExitToday,Lots,Q_AskPrice() ,orderIds,\"\",\"\",A_AccountIndex(A_AccountID(),A_BrokerID()));
OrderID=orderIds[0];
Commentary(\"空头止损:\"+Text(Lots)+\"手\");
Print(Text(Time())+\":空头止损:\"+Text(Lots)+\"手\");
}
}
}
}
//如当前持仓为零,开仓条件为连续两个k线低点抬高即第2根k线最低点比第1根k线最低点要高,
//而后第3根k线一开始运行时即以第1根k线最低价+3个点下单买入开仓(设止损3个点)。
//第三根k线价格只要到了第一个k线最低价+3跳 不需要大于前一个最低价 即买入
condLong=Data1.L[1]>Data1.L[2] And L<=Data1.L[2]+ Add*MinPoint And Open>= Data1.L[2];
condShort=Data1.H[1]<Data1.H[2] And H>=Data1.H[2]- Add*MinPoint And Open<= Data1.H[2];
//符合多头开仓条件
If (condLong And Not (Data1.H[1]<Data1.H[2]) And IsNewBar==0 And MPL==0)
{
//计算理论成交价格
myPrice=Min(Open,Data1.L[2]+ Add*MinPoint);
PlotString(\"买卖\",\"买开↑(\"+Text(myPrice)+\")\",L-1*MinPoint,Red);
IsNewBar=1;
//计算止损价格
LossPrice=myPrice-Loss*MinPoint;
//Print(\"A_BrokerID:\"+Text(A_BrokerID()));
//开仓
If (Recall==1)
{
//支持回溯
If (MarketPosition<>1 And Vol>0)
{
Buy(Lots,myPrice);
MPL=1;
MPS=0;
BS=0;
}
}Else
{
//不支持回溯
Position pos;
Bool ret = A_GetPosition(myContract, pos, \"\", 0);
//Commentary(\"A_GetPosition:\" + IIFString(ret, \"True\", \"False\") + \",\" + Text(pos));
If (ret)
{
Commentary(\"多头可平仓:\"+Text(pos.longCanSellVolume));
Commentary(\"空头可平仓:\"+Text(pos.shortCanCoverVolume));
MPL=Max(pos.longCanSellVolume,1);
MPS=Max(pos.shortCanCoverVolume,1);
If (MPL==1 And BarStatus==2) Print(Text(Time())+\":MPL=\"+Text(MPL));
If (MPS==1 And BarStatus==2) Print(Text(Time())+\":MPS=\"+Text(MPS));
Array<Integer> orderIds; //委托ID
//Print(\"A_BrokerID:\"+Text(A_BrokerID()));
If (MPL<>1 And Vol>0 And BarStatus==2)
{
A_SendOrderEx(myContract,Enum_Buy,Enum_Entry,Lots,Q_ASKPrice() ,orderIds,\"\",\"\",A_AccountIndex(A_AccountID(),A_BrokerID()));
OrderID=orderIds[0];
Commentary(\"多头开仓:\"+Text(Lots)+\"手\");
Print(Text(Time())+\":多头开仓:\"+Text(Lots)+\"手\");
LossPrice=Q_ASKPrice()-Loss*MinPoint;
BS=0;
}
}
}
}
//符合空头开仓条件
If (condShort And Not (Data1.L[1]>Data1.L[2]) And IsNewBar==0 And MPS==0)
{
//计算理论成交价格
myPrice=Max(Open,Data1.H[2]- Add*MinPoint);
PlotString(\"买卖\",\"卖开↓(\"+Text(myPrice)+\")\",H+1*MinPoint,Green);
IsNewBar=1;
//计算止损价格
LossPrice=myPrice+Loss*MinPoint;
//开仓
If (Recall==1)
{
//支持回溯
If (MarketPosition<>-1 And Vol>0)
{
SellShort(Lots,myPrice);
MPL=0;
MPS=1;
BS=0;
}
}Else
{
//不支持回溯
Position pos;
Bool ret = A_GetPosition(myContract, pos, \"\", 0);
//Commentary(\"A_GetPosition:\" + IIFString(ret, \"True\", \"False\") + \",\" + Text(pos));
If (ret)
{
Commentary(\"多头可平仓:\"+Text(pos.longCanSellVolume));
Commentary(\"空头可平仓:\"+Text(pos.shortCanCoverVolume));
MPL=Max(pos.longCanSellVolume,1);
MPS=Max(pos.shortCanCoverVolume,1);
If (MPL==1 And BarStatus==2) Print(Text(Time())+\":MPL=\"+Text(MPL));
If (MPS==1 And BarStatus==2) Print(Text(Time())+\":MPS=\"+Text(MPS));
Array<Integer> orderIds; //委托ID
If (MPS<>1 And Vol>0 And BarStatus==2)
{
A_SendOrderEx(myContract,Enum_Sell,Enum_Entry,Lots,Q_BidPrice() ,orderIds,\"\",\"\",A_AccountIndex(A_AccountID(),A_BrokerID()));
OrderID=orderIds[0];
Commentary(\"空头开仓:\"+Text(Lots)+\"手\");
Print(Text(Time())+\":空头开仓:\"+Text(Lots)+\"手\");
LossPrice=Q_BidPrice()+Loss*MinPoint;
BS=0;
}
}
}
}
//止损
If (BS>=0 And ( (MPL==1 And Low<=LossPrice) Or (MPS==1 And High>=LossPrice)))
{
//多头离场
If (Recall==1)
{
//支持回溯
If (MarketPosition==1 And Vol>0)
{
myPrice=Min(Open,LossPrice);
Sell(Lots,myPrice);
MPL=0;
MPS=0;
Commentary(\"止损平仓\");
}
If (MarketPosition==-1 And Vol>0)
{
myPrice=Max(Open,LossPrice);
BuyToCover(Lots,myPrice);
MPL=0;
MPS=0;
Commentary(\"止损平仓\");
}
}Else
{
//不支持回溯
Position pos;
Bool ret = A_GetPosition(myContract, pos, \"\", 0);
//Commentary(\"A_GetPosition:\" + IIFString(ret, \"True\", \"False\") + \",\" + Text(pos));
If (ret)
{
Commentary(\"多头可平仓:\"+Text(pos.longCanSellVolume));
Commentary(\"空头可平仓:\"+Text(pos.shortCanCoverVolume));
MPL=Max(pos.longCanSellVolume,1);
MPS=Max(pos.shortCanCoverVolume,1);
//If (MPL==1 And BarStatus==2) Print(Text(Time())+\":MPL=\"+Text(MPL));
//If (MPS==1 And BarStatus==2) Print(Text(Time())+\":MPS=\"+Text(MPS));
Array<Integer> orderIds; //委托ID
//Print(\"A_BrokerID:\"+Text(A_BrokerID()));
If (MPL==1 And Vol>0 And BarStatus==2)
{
A_SendOrderEx(myContract,Enum_Sell,Enum_ExitToday,Lots,Q_BidPrice() ,orderIds,\"\",\"\",A_AccountIndex(A_AccountID(),A_BrokerID()));
OrderID=orderIds[0];
Commentary(\"多头止损:\"+Text(Lots)+\"手\");
Print(Text(Time())+\":多头止损:\"+Text(Lots)+\"手\");
}
If (MPS==1 And Vol>0 And BarStatus==2)
{
A_SendOrderEx(myContract,Enum_Buy,Enum_ExitToday,Lots,Q_AskPrice() ,orderIds,\"\",\"\",A_AccountIndex(A_AccountID(),A_BrokerID()));
OrderID=orderIds[0];
Commentary(\"空头止损:\"+Text(Lots)+\"手\");
Print(Text(Time())+\":空头止损:\"+Text(Lots)+\"手\");
}
}
}
}
//如开仓成交则在成交后第7根k线运行至第50秒时平仓
If (BS>=Exit And Second()>=EtSecond And MPL+MPS>0)
{
myPrice=Open;
//多头离场
If (Recall==1)
{
//支持回溯
If (MarketPosition==1 And Vol>0)
{
Sell(Lots,myPrice);
MPL=0;
MPS=0;
Commentary(\"多头离场\");
}
If (MarketPosition==-1 And Vol>0)
{
BuyToCover(Lots,myPrice);
MPL=0;
MPS=0;
Commentary(\"空头离场\");
}
}Else
{
//不支持回溯
Position pos;
Bool ret = A_GetPosition(myContract, pos, \"\", 0);
//Commentary(\"A_GetPosition:\" + IIFString(ret, \"True\", \"False\") + \",\" + Text(pos));
If (ret)
{
Commentary(\"多头可平仓:\"+Text(pos.longCanSellVolume));
Commentary(\"空头可平仓:\"+Text(pos.shortCanCoverVolume));
MPL=Max(pos.longCanSellVolume,1);
MPS=Max(pos.shortCanCoverVolume,1);
//If (MPL==1 And BarStatus==2) Print(Text(Time())+\":MPL=\"+Text(MPL));
//If (MPS==1 And BarStatus==2) Print(Text(Time())+\":MPS=\"+Text(MPS));
Array<Integer> orderIds; //委托ID
//Print(\"A_BrokerID:\"+Text(A_BrokerID()));
If (MPL==1 And Vol>0 And BarStatus==2)
{
A_SendOrderEx(myContract,Enum_Sell,Enum_ExitToday,Lots,Q_BidPrice() ,orderIds,\"\",\"\",A_AccountIndex(A_AccountID(),A_BrokerID()));
OrderID=orderIds[0];
Commentary(\"多头平仓:\"+Text(Lots)+\"手\");
Print(Text(Time())+\":多头平仓:\"+Text(Lots)+\"手\");
}
If (MPS==1 And Vol>0 And BarStatus==2)
{
A_SendOrderEx(myContract,Enum_Buy,Enum_ExitToday,Lots,Q_AskPrice() ,orderIds,\"\",\"\",A_AccountIndex(A_AccountID(),A_BrokerID()));
OrderID=orderIds[0];
Commentary(\"空头平仓:\"+Text(Lots)+\"手\");
Print(Text(Time())+\":空头平仓:\"+Text(Lots)+\"手\");
}
}
}
}
}
//成交更新事件函数,参数ordFill表示更新的成交结构体
OnFill(FillRef ordFill)
{
If (ordFill.side==Enum_Buy)
{
If (ordFill.comboffset==Enum_Entry) //多头开仓,id1成交
{
MPL=1;
BS=0;
}
}
If (ordFill.side==Enum_Sell)
{
If (ordFill.comboffset==Enum_Entry) //空头开仓,id1成交
{
MPS=1;
BS=0;
}
}
If (ordFill.side==Enum_Buy)
{
If (ordFill.comboffset==Enum_ExitToday) //空头平仓,id1成交
{
MPS=0;
}
}
If (ordFill.side==Enum_Sell)
{
If (ordFill.comboffset==Enum_ExitToday) //多头平仓,id1成交
{
MPL=0;
}
}
}
//------------------------------------------------------------------------
// 编译版本 2023/03/15 092840
// 版权所有 sweer1234
// 更改声明 TradeBlazer Software保留对TradeBlazer平台
// 每一版本的TradeBlazer公式修改和重写的权利
//------------------------------------------------------------------------
设置一个变量big_con=0 执行一次后big_con=1,加到开仓条件里
这个无法控制,因为只写了一句A_SenderOrderEx()。但是由于存在多个数据源Data,导致程序自动产生了多条订单。
你的代码里使用了2个数据源,data0和data1,在使用A_SendOrderEx()时,没有在前面加数据源限定,所以就默认在两个数据源上同时发送订单了。可以修改为:data0.A_SendOrderEx()试试。
没有加前缀,也没有用range包起来,那么默认只对data0图层执行
我测试了,结果确实存在和楼主一样的情况:
预置条件:
单次开仓手数:1手
总持仓上限:1手
商品合约:sp888
测试步骤:
1、在策略交易中只添加一个sp888商品合约,程序正确交易1手持仓。
2、在策略交易中只添加一个sp888商品合约后,再添加1个合约的不同周期数据源,则会出现不想要的2手持仓。
3、在策略交易中只添加一个sp888商品合约后,又添加4个合约的不同周期数据源,则会出现不想要的10手持仓。
另外,策略交易中给出的1手空仓数据是正确的。但实际持仓中的2、10手持仓数据就与期望不符了。
结果情况如下图所示:
你是不是先用了策略交易执行自动交易,然后交易单元打开了k线 也加载头寸执行了自动交易?
我只建了K线策略单元,在K线图上要点击启动自动交易,策略才会自动发单
那就不太清楚了 建议写日志跟踪程序的运行路径 看看每次报单的操作源到底是哪里