此自动交易模型模板将在新版本1.8中发布,此模板具有自动开仓,自动加仓,自动平单和撤单的功能!精确控制仓位,实现资金管理! 本模板适合2条线交叉产生信号,金钱豹将公布更多形式自动交易模板! Code: public List<Object> JqbMaSr(List<Object> listObjectIn) { //输入参数由数组分解为单个.Net对象 Int32 label = (Int32)listObjectIn[0];//品种代码 List<float> closeList = (List<float>)listObjectIn[1];//收盘价格 List<float> openList = (List<float>)listObjectIn[2];//开盘价格 List<float> highList = (List<float>)listObjectIn[3];//最高价格 List<float> lowList = (List<float>)listObjectIn[4];//最低价格 List<float> volList = (List<float>)listObjectIn[5];//成交量 List<float> amountList = (List<float>)listObjectIn[6];//成交额 List<UInt32> timeList = (List<UInt32>)listObjectIn[7];//时间 //相关性选择的品种代码分别是: //990001/999001/ Dictionary<Int32, List<JqbHistory>> jqbHistoryMinuteOneTodayDict = (Dictionary<Int32, List<JqbHistory>>)listObjectIn[8];//今天1分钟周期数据 JqbHistory 中分别为收、开、高、低、量、额 、时! //启用了相关性选择数据,请从上面相关性列表中提取对应品种数据! Dictionary<Int32, List<JqbReportForClientDict>> jqbReportForClientTodayDict = (Dictionary<Int32, List<JqbReportForClientDict>>)listObjectIn[9];//今天及时行情数据 JqbHistory 中分别为 最新、量、额 、时! //启用了相关性选择数据,请从上面相关性列表中提取对应品种数据! UInt32 zhouQi = (UInt32)listObjectIn[10];//当前K线图形周期 Dictionary<Int32, JqbBuySellClass> jqbBuySellDict = (Dictionary<Int32, JqbBuySellClass>)listObjectIn[11];// 盘口买卖信息! //启用了相关性选择数据,请从上面相关性列表中提取对应品种数据! Dictionary<Int32, JqbDllPanKou> jqbPanKouDict = (Dictionary<Int32, JqbDllPanKou>)listObjectIn[12];//盘口数据 开 高低收 涨跌停等数据 ! //启用了相关性选择数据,请从上面相关性列表中提取对应品种数据! JqbCtpZhangHaoClass jqbCtpZhangHaoClass = (JqbCtpZhangHaoClass)listObjectIn[13];//Ctp账号数据! CtpAccount ctpAccount = jqbCtpZhangHaoClass.CtpAccount;//Ctp资金数据! List<CtpCangDan> ctpCangdanList = jqbCtpZhangHaoClass.CtpCangdanList;//Ctp仓单数据! List<CtpOrder> ctpOrderList = jqbCtpZhangHaoClass.CtpOrderList;//Ctp订单回报数据! List<CtpTrade> ctpTradeList = jqbCtpZhangHaoClass.CtpTradeList;//Ctp成交回报数据! //输入参数分解完毕,可以发挥您的智慧,在下面添加您自己的分析代码了! #region 计算要交叉发出信号的数据 Int32 nSecond1 = 10; Int32 nSecond2 = 20;//30 List<float> ma10 = JqbZhiBiaoForZhuTu.JqbMa(closeList, nSecond1 ); List<float> ma30 = JqbZhiBiaoForZhuTu.JqbMa(closeList, nSecond2 ); #endregion 计算要交叉发出信号的数据 List<object> listObjectOut = new List<object>();//输出对象集合 List<List<float>> quXianListOut = new List<List<float>>();//绘制多条曲线 List<float> chuiZhiListOut = new List<float>();//绘制垂直线 List<string> textBlockListOut = new List<string>();//图中写文字 string debugStringOut = "";//调试文字信息 List<JqbOrderClass> jqbOrderList = new List<JqbOrderClass>();//多订单发送 quXianListOut.Add(ma10);//将交叉数据显示在K线图 quXianListOut.Add(ma30);//将交叉数据显示在K线图 #region 订单发送否信号处理 string xinHaoLast = "";//避免2次开相同方向的订单 for (Int32 i = 0; i <timeList .Count; i++)//创建买卖信号 { chuiZhiListOut.Add(-1); textBlockListOut.Add(""); if (i > nSecond2 ) { if (ma10[i - 1] < ma30[i - 1] && ma10[i - 2] >= ma30[i - 2] && xinHaoLast != "卖出") {//=避免有的信号出现不了 chuiZhiListOut[i] = 4; //绿色 跌 textBlockListOut[i] = "卖出"; xinHaoLast = "卖出"; //debugStringOut += " ma10[i]=" + ma10[i].ToString() + " ma10[i-1]=" + ma10[i - 1].ToString() + " ma10[i - 2]=" + ma10[i - 2].ToString() + " ma30[i]=" + ma30[i].ToString() + " ma30[i - 1]=" + ma30[i - 1].ToString() + " ma30[i - 2]=" + ma30[i - 2].ToString(); } if (ma10[i - 1] > ma30[i - 1] && ma10[i - 2] <= ma30[i - 2] && xinHaoLast != "买入") { chuiZhiListOut[i] = 1; //红色 涨 textBlockListOut[i] = "买入"; xinHaoLast = "买入"; //debugStringOut += " ma10[i]=" + ma10[i].ToString() + " ma10[i-1]=" + ma10[i - 1].ToString() + " ma10[i - 2]=" + ma10[i - 2].ToString() + " ma30[i]=" + ma30[i].ToString() + " ma30[i - 1]=" + ma30[i - 1].ToString() + " ma30[i - 2]=" + ma30[i - 2].ToString(); } //测试时,可以用下面代码,避免正式信号时间等待太长时间 //if (i % 6 ==0) //{//=避免有的信号出现不了 // chuiZhiListOut[i] = 4; //绿色 跌 // textBlockListOut[i] = "卖出"; // xinHaoLast = "卖出"; // //debugStringOut += " ma10[i]=" + ma10[i].ToString() + " ma10[i-1]=" + ma10[i - 1].ToString() + " ma10[i - 2]=" + ma10[i - 2].ToString() + " ma30[i]=" + ma30[i].ToString() + " ma30[i - 1]=" + ma30[i - 1].ToString() + " ma30[i - 2]=" + ma30[i - 2].ToString(); //} //else //{ // if ( i %3==0) // { // chuiZhiListOut[i] = 1; //红色 涨 // textBlockListOut[i] = "买入"; // xinHaoLast = "买入"; // //debugStringOut += " ma10[i]=" + ma10[i].ToString() + " ma10[i-1]=" + ma10[i - 1].ToString() + " ma10[i - 2]=" + ma10[i - 2].ToString() + " ma30[i]=" + ma30[i].ToString() + " ma30[i - 1]=" + ma30[i - 1].ToString() + " ma30[i - 2]=" + ma30[i - 2].ToString(); // } //} } else { //if (i == 1) //{ // if (openList[1] < ma30[0]) // { // chuiZhiListOut[i] = 4; //绿色 跌 // textBlockListOut[i] = "卖出"; // } // if (openList[1] > ma30[0]) // { // chuiZhiListOut[i] = 1; //红色 涨 // textBlockListOut[i] = "买入"; // } //} } } #region 发送新信号时,是开始发送一次订单还是间隔几秒后加仓 bool orderSendMulTime = true ;//客户手动定义此值 true时:订单发送多次或者多次检查并撤单和加仓,false时:只在信号开始时开一次仓,后面不检查 bool orderSendThisTime = false;//本次是否发送订单 bool orderDelThisTime = false;//本次订单是否撤销 Int32 jianGeSendOrder=4;//4秒间隔比较适合 多订单发送时,避免每0.5秒发送频率过高而持仓未及时更新 Int32 jianGeDelOrder = 2;//2设置要注意,间隔为6时,此可为3,依次是上面加仓间隔的一半比较合适 //开仓订单撤销和加仓不能在同一时间,需间隔2秒以上,否则,撤销订单失败时,加仓成功,总仓位会超出 //撤销平仓订单时,发送后需间隔 0.2秒,再次发送平仓订单,避免有的冻结单在再次平仓时出现问题。 if (textBlockListOut.Last().ToString() == "买入" || textBlockListOut.Last().ToString() == "卖出")//textBlockListOut最后一个有买卖信号时 { debugStringOut += " IF "; List<UInt32> timeListLastZhou = new List<uint>(); //最后周期单元中时间list 只能通过jqbReportList中的时间计算,timeList中的最后一格时间都是固定该格的起始时间 debugStringOut += " zhouQi=" + zhouQi.ToString(); if (jqbReportForClientTodayDict.ContainsKey(label)) { List<JqbReportForClientDict> jqbReportList = jqbReportForClientTodayDict[label]; for (Int32 i = 0; i < jqbReportList.Count; i++) //过滤重复发出买卖信号 倒循环后面部分数据 { //debugStringOut += " i=" + i.ToString() + " [i]=" + jqbReportList[i].mtime.ToString(); if (Math.Floor(((double)jqbReportList[jqbReportList.Count - 1 - i].mtime) / zhouQi) == Math.Floor(((double)jqbReportList.Last().mtime) / zhouQi)) { timeListLastZhou.Add(jqbReportList[jqbReportList.Count - 1 - i].mtime); } else { break;//不是同一周期时,停止循环 } } debugStringOut += " timeListLastZhou count=" + timeListLastZhou.Count.ToString(); if (orderSendMulTime == false) //单次发送时 { if (timeListLastZhou.Count == 1) { orderSendThisTime = true; } debugStringOut += " 单次发送时:"; } else//多次发送时 { if (timeListLastZhou.Count == 1) //开始第一个 一定发送 { orderSendThisTime = true; debugStringOut += " 多次发送时(count=1):"; } else//>1时 { Int32 countOflastTime=0 ; foreach (UInt32 timeTmp in timeListLastZhou ) { if (timeTmp == timeListLastZhou.Max())//统计9:30:01的个数,由于0.5秒发送一次,会存在一个秒数上多个数据的情形,只在其首个上发送信号 countOflastTime++; } if ((timeListLastZhou.Max() > timeListLastZhou.Min()) && countOflastTime ==1) //每5秒间隔发送一次,至少1秒以上间隔,同时,最新一秒内只收到一次数据时(存在0.5秒,但此计数雷同,避免重复发送) { if ((timeListLastZhou.Max() - timeListLastZhou.Min()) % jianGeSendOrder == 0) {//在开始信号后面,每隔jianGeSendOrder 4秒,检查一次是否要加仓 orderSendThisTime = true; debugStringOut += " 多次发送时(count>1):"; } else {//在非4秒点位时 if ((timeListLastZhou.Max() - timeListLastZhou.Min()) % jianGeDelOrder == 0) {//否则在间隔2秒时,检查是否要撤单 orderDelThisTime = true; debugStringOut += " 多次发送时(count>1)本次会撤销订单:"; } } } } } } debugStringOut += "有信号 本次发送否:" + orderSendThisTime.ToString() + " " + JqbConvert.ConvertTimeToDateTime(timeListLastZhou.Max ()).ToString(); } #endregion 发送新信号时,是开始发送一次订单还是间隔几秒后加仓 #endregion 订单发送否信号处理 Int32 indexOfOrder = 0; string jiaoYiCode = JqbGetLabelAndName.GetQihuoJiaoYiCode(label); #region 撤销订单 if (orderDelThisTime == true) { bool sleepBool = false; for (Int32 i = 0; i < ctpOrderList.Count; i++) { if (i > 300) //当订单循环300次检查时,自动终止循环,避免过多订单时循环浪费Cpu 过小时会取消不了 break; CtpOrder ctpOrder = ctpOrderList[ctpOrderList.Count - 1 - i]; //倒循环 if (ctpOrder.InstrumentID == jiaoYiCode && ctpOrder.VolumeTotal > 0 && ctpOrder.OrderStatus.ToString() != "Canceled") {//取消该合约的所有未成交订单 JqbOrderDel(jqbOrderList, ctpOrder.InstrumentID, ctpOrder.ExchangeID, ctpOrder.FrontID, ctpOrder.SessionID, ctpOrder.OrderRef, indexOfOrder++); debugStringOut += " 撤销订单已经从Dll发送! "; sleepBool = true; } } if (sleepBool == true) { Thread.Sleep(1000);//有撤销订单时,执行完毕休息0.2秒,再执行其他动作! 待测此项!2010 03 18 debugStringOut += " Sleeped! "; } } #endregion 撤销订单 if (orderSendThisTime == true) { float zhiXinDu = 0.4f;//例如 9手 置信度为40%,则 为4手 Int32 priceForOpenJiaCha = 2;//开仓价差单位 Int32 priceForCloseJiaCha=5;//平仓时价差 string pinZhong = JqbConvert.JqbGetQihuoPinZhongFromInstrume(jiaoYiCode); double bianDongDanWei = 1d; //最小变动价格单位 bianDongDanWei = JqbGetLabelAndName.JqbGetPricChangeDanWeiMin(pinZhong); Int32 dunShu = JqbQihuoAvlHuanShan.GetQihuoDunShuK(pinZhong); Int32 chiCangMax = 100;//最大尺寸数量,可以调整或者由资金量按照资金占用量计算 if (pinZhong == JqbGetLabelAndName.jqbQhPzForCu )//通过不同品种,修改最大持仓量 chiCangMax = 50; if (pinZhong == JqbGetLabelAndName.jqbQhPzForA ) chiCangMax = 80; if (pinZhong == JqbGetLabelAndName.jqbQhPzForC ) chiCangMax = 200; if (pinZhong == JqbGetLabelAndName.jqbQhPzForRu) chiCangMax = 60; debugStringOut += " Dll textBlock=" + textBlockListOut.Last() + " count=" + closeList.Count.ToString() + " " + DateTime.Now.ToString(); if (textBlockListOut.Last() == "买入") { #region 平卖出单 double priceForPing = 0; if (jqbBuySellDict.ContainsKey(label)) { if (jqbBuySellDict[label].SellPrice1 < closeList[closeList.Count - 2] + priceForOpenJiaCha * bianDongDanWei)//计算本次开仓价格 {//价格超出一定距离时,不赋值,后面代码不开仓 priceForPing = jqbBuySellDict[label].SellPrice1 + priceForCloseJiaCha * bianDongDanWei; } } if (priceForPing > 0) { Int32 positionForPingForToday = 0;//已经有的持仓量 今仓 Int32 positionForPingForYesterday = 0;//已经有的持仓量 今仓 foreach (CtpCangDan ctpCangDan in ctpCangdanList) //计算本次开仓量 { if (ctpCangDan.InstrumentID == jiaoYiCode && ctpCangDan.Direction == "卖") { positionForPingForToday = (Int32)(ctpCangDan.OpenVolume - ctpCangDan.DongJieVol);//2010 03 18 add 修正冻结的情况 if (positionForPingForToday < 0) { positionForPingForYesterday = (Int32)(ctpCangDan.YdPosition + positionForPingForToday); positionForPingForToday = 0; } else { positionForPingForYesterday = (Int32)ctpCangDan.YdPosition; } } } if (orderSendMulTime == true) //当多次发送订单时,考虑盘口量 否则一次全部平掉 { if (positionForPingForToday + positionForPingForYesterday > jqbBuySellDict[label].SellVolume1 * zhiXinDu) {//需平量比较多时,否则量少一次可平 positionForPingForYesterday = (Int32)Math.Min(positionForPingForYesterday, jqbBuySellDict[label].SellVolume1 * zhiXinDu);//先平昨 positionForPingForToday = (Int32)Math.Min(positionForPingForToday, jqbBuySellDict[label].SellVolume1 * zhiXinDu - positionForPingForYesterday);//平昨后,剩余可平卖盘和今平量取最小值执行平仓 } } if (positionForPingForToday > 0) { debugStringOut += " 本次将发送平仓订单 买入平今仓! 平量:" + positionForPingForToday.ToString(); JqbOrderInsert(jqbOrderList, jiaoYiCode, priceForPing, CTPDirectionType.Buy, positionForPingForToday, OffsetFlagType.CloseToday, indexOfOrder++); } if (positionForPingForYesterday > 0) { debugStringOut += " 本次将发送平仓订单 买入平昨仓 ! 平量:" + positionForPingForYesterday.ToString(); JqbOrderInsert(jqbOrderList, jiaoYiCode, priceForPing, CTPDirectionType.Buy, positionForPingForYesterday, OffsetFlagType.Close, indexOfOrder++); } } #endregion 平卖出单 #region 开仓买入 //平仓在前时,需考虑平仓吃掉的买卖盘数量影响,同时,考虑平仓后,资金供应量增加。但资金供应考虑时要有0.2秒间隔,否则平单为成交时资金未到位!? double priceForOpen = 0; Int32 volToOpen = 0; #region 开仓价格计算 if (jqbBuySellDict.ContainsKey(label)) { if (jqbBuySellDict[label].SellPrice1 < closeList[closeList.Count - 2] + priceForOpenJiaCha * bianDongDanWei)//计算本次开仓价格 {//价格超出一定距离时,不赋值,后面代码不开仓 priceForOpen = jqbBuySellDict[label].SellPrice1; } } #endregion 开仓价格计算 #region 开仓量计算 //增加资金计算数量比较 //ctpAccount .Available Int32 volAvail = (Int32)Math.Floor(ctpAccount.Available / (priceForOpen * 1.001 * dunShu * 0.13f));//资金可以开的单数量 注意0.13f,保证金比例,程序中不能过小 if (volAvail > 0) { Int32 position = 0;//已经有的持仓量 foreach (CtpCangDan ctpCangDan in ctpCangdanList) //计算本次开仓量 { if (ctpCangDan.InstrumentID == jiaoYiCode && ctpCangDan.Direction == "买") { position = (Int32)ctpCangDan.Position; } } debugStringOut += " 持仓:" + position.ToString(); Int32 volCanToOpen = chiCangMax - position;//最大持仓量-已经持仓量=还可以开的量 debugStringOut += " volCanToOpen=" + volCanToOpen.ToString() + " "; if (orderSendMulTime == true) //当多次发送订单时,考虑盘口量 { volToOpen = (Int32)Math.Min(volCanToOpen, jqbBuySellDict[label].SellVolume1 * zhiXinDu); //还可以开的量和盘口量置信度比较 } else //单次发送时,不考虑盘口量,一次开满 { volToOpen = volCanToOpen; } volToOpen = Math.Min(volToOpen, volAvail);//在资金范围内开仓量 } #endregion 开仓量计算 debugStringOut += " price=" + priceForOpen.ToString() + " vol=" + volToOpen.ToString(); if (priceForOpen > 0.001d && volToOpen > 0) { debugStringOut += " 本次将发送订单 "; JqbOrderInsert(jqbOrderList, jiaoYiCode, priceForOpen, CTPDirectionType.Buy, volToOpen, OffsetFlagType.Open, indexOfOrder++); } else { debugStringOut += " 由于价格或者数量为0 ,本次不发送订单! "; } #endregion 开仓买入 } if (textBlockListOut.Last() == "卖出") { #region 平买入单 卖平 double priceForPing = 0; if (jqbBuySellDict.ContainsKey(label)) { if (jqbBuySellDict[label].BuyPrice1 > closeList[closeList.Count - 2] - priceForCloseJiaCha * bianDongDanWei)//计算本次开仓价格 {//价格超出一定距离时,不赋值,后面代码不开仓 priceForPing = jqbBuySellDict[label].BuyPrice1 - priceForCloseJiaCha * bianDongDanWei;//为迅速平仓,按照价差发送 } } if (priceForPing > 0) { Int32 positionForPingForToday = 0;//已经有的持仓量 今仓 Int32 positionForPingForYesterday = 0;//已经有的持仓量 今仓 foreach (CtpCangDan ctpCangDan in ctpCangdanList) //计算本次开仓量 { if (ctpCangDan.InstrumentID == jiaoYiCode && ctpCangDan.Direction == "买") { positionForPingForToday = (Int32)(ctpCangDan.OpenVolume - ctpCangDan.DongJieVol);//2010 03 18 add 修正冻结的情况 if (positionForPingForToday < 0) { positionForPingForYesterday = (Int32)(ctpCangDan.YdPosition + positionForPingForToday); positionForPingForToday = 0; } else { positionForPingForYesterday = (Int32)ctpCangDan.YdPosition; } } } if (orderSendMulTime == true) //当多次发送订单时,考虑盘口量 否则一次全部平掉 { if (positionForPingForToday + positionForPingForYesterday > jqbBuySellDict[label].BuyVolume1 * zhiXinDu) {//需平量比较多时,否则量少一次可平 positionForPingForYesterday = (Int32)Math.Min(positionForPingForYesterday, jqbBuySellDict[label].BuyVolume1 * zhiXinDu);//先平昨 positionForPingForToday = (Int32)Math.Min(positionForPingForToday, jqbBuySellDict[label].BuyVolume1 * zhiXinDu - positionForPingForYesterday);//平昨后,剩余可平卖盘和今平量取最小值执行平仓 } } if (positionForPingForToday > 0) { debugStringOut += " 本次将发送平仓订单 卖出平今仓! 平量:" + positionForPingForToday.ToString(); JqbOrderInsert(jqbOrderList, jiaoYiCode, priceForPing, CTPDirectionType.Sell, positionForPingForToday, OffsetFlagType.CloseToday, indexOfOrder++); } if (positionForPingForYesterday > 0) { debugStringOut += " 本次将发送平仓订单 卖出平昨仓 ! 平量:" + positionForPingForYesterday.ToString(); JqbOrderInsert(jqbOrderList, jiaoYiCode, priceForPing, CTPDirectionType.Sell, positionForPingForYesterday, OffsetFlagType.Close, indexOfOrder++); } } #endregion 平买入单 #region 开仓卖出 //平仓在前时,需考虑平仓吃掉的买卖盘数量影响,同时,考虑平仓后,资金供应量增加。但资金供应考虑时要有0.2秒间隔,否则平单为成交时资金未到位!? double priceForOpen = 0; Int32 volToOpen = 0; #region 开仓价格计算 if (jqbBuySellDict.ContainsKey(label)) { if (jqbBuySellDict[label].BuyPrice1 > closeList[closeList.Count - 2] - priceForOpenJiaCha * bianDongDanWei)//计算本次开仓价格 {//价格超出一定距离时,不赋值,后面代码不开仓 priceForOpen = jqbBuySellDict[label].BuyPrice1; } } #endregion 开仓价格计算 #region 开仓量计算 //增加资金计算数量比较 //ctpAccount .Available Int32 volAvail = (Int32)Math.Floor(ctpAccount.Available / (priceForOpen * 1.001 * dunShu * 0.13f));//资金可以开的单数量 注意0.13f,保证金比例,程序中不能过小 if (volAvail > 0) { Int32 position = 0;//已经有的持仓量 foreach (CtpCangDan ctpCangDan in ctpCangdanList) //计算本次开仓量 { if (ctpCangDan.InstrumentID == jiaoYiCode && ctpCangDan.Direction == "卖") { position = (Int32)ctpCangDan.Position; } } debugStringOut += " 持仓:" + position.ToString(); Int32 volCanToOpen = chiCangMax - position;//最大持仓量-已经持仓量=还可以开的量 debugStringOut += " volCanToOpen=" + volCanToOpen.ToString() + " "; if (orderSendMulTime == true) //当多次发送订单时,考虑盘口量 { volToOpen = (Int32)Math.Min(volCanToOpen, jqbBuySellDict[label].BuyVolume1 * zhiXinDu); //还可以开的量和盘口量置信度比较 } else //单次发送时,不考虑盘口量,一次开满 { volToOpen = volCanToOpen; } volToOpen = Math.Min(volToOpen, volAvail);//在资金范围内开仓量 } #endregion 开仓量计算 debugStringOut += " price=" + priceForOpen.ToString() + " vol=" + volToOpen.ToString(); if (priceForOpen > 0.001d && volToOpen > 0) { debugStringOut += " 本次将发送订单 "; JqbOrderInsert(jqbOrderList, jiaoYiCode, priceForOpen, CTPDirectionType.Sell , volToOpen, OffsetFlagType.Open, indexOfOrder++); } else { debugStringOut += " 由于价格或者数量为0 ,本次不发送订单! "; } #endregion 开仓卖出 } } listObjectOut.Add(quXianListOut); listObjectOut.Add(chuiZhiListOut); listObjectOut.Add(textBlockListOut); listObjectOut.Add(debugStringOut); listObjectOut.Add(jqbOrderList); return listObjectOut; }