跨平台跟单系统的实现方式和技术原理(ClientApi篇)

发布于 2020-01-04 00:22:59

话说ClientApi,市面上常见的有Mt4ServerApi,Mt4ClientApi,mt4Api。其实都是第三方编写的,这里统称为ClientApi,虽然其实现语言也相同(C++,C#,Java,PHP。但原理完全一样,无非是获取终端信息MD5加密后与该平台服务器建立连接,然后发送订单相关的指令。

下面以Mt4ClientApi为例,讲解下第三方跟单的实现方式,如图

image.png

首先实例化2个连接池,分别是信号源池和跟单账号池,当监听到信号订单变化后,查找策略池中账号对应关系,然后进行相关策略和跟单账号进行订单操作。其主要的跟单过程如下:

#region 多线程跟单
void OrderThread(object obj)
{
    FollowOrderPara fop = (FollowOrderPara)obj;
    RFollowAcc fa = fop.RFA;
    string opDis = "未知操作";
    switch (fop.UpDate)
    {
        case "PositionOpen"://开仓0
        case "PendingOpen"://挂单3
            opDis = "开仓";
            break;
        case "PositionClose"://平仓1
        case "PendingClose"://删除挂单 4
            opDis = "平仓";
            break;
        case "PositionModify"://修改2
            opDis = "修改";
            break;
    }
    try
    { 
        Order lOrder = fop.LO;//喊单order

        Order fOrder = null;//跟单order
        QuoteClient qcFollow = QuoteClientPools.GetQuoteClien(fa.Fid); //跟单连接qc
        if (qcFollow == null) return;

        OrderClient ocFollow = new OrderClient(qcFollow);

        double vo = lOrder.Lots;//手数
        Op type = lOrder.Type;//交易类型 买 卖 挂
        double sl = lOrder.StopLoss;//止盈
        double tp = lOrder.TakeProfit;//止损
        double price = lOrder.OpenPrice;//价格取跟单价格
        string sym = lOrder.Symbol;//品种对照

        switch (fop.UpDate)
        {
            case "PositionOpen"://开仓0
            case "PendingOpen"://挂单3 
                               //根据策略取相应的跟单ID 手数 止盈止损 交易类型

                if (fa.FollowType == "只跟多单" && type != Op.Buy)
                {
                    return;
                }
                if (fa.FollowType == "只跟空单" && type != Op.Sell)
                {
                    return;
                }
                
                switch (fa.VolumeMode)
                {
                    case "固定手数":
                        vo = fa.VolumeMultiple;
                        break;
                    case "倍数跟单":
                        vo = lOrder.Lots * fa.VolumeMultiple;//计算跟单手数
                        break;
                    case "比例跟单":
                        //逻辑未明确
                        break;
                }

                if (fa.Direction == "反")//跟单方向
                {
                    sl = lOrder.TakeProfit;
                    tp = lOrder.StopLoss;
                    switch (lOrder.Type)
                    {
                        case Op.Buy:
                            type = Op.Sell;
                            break;
                        case Op.Sell:
                            type = Op.Buy;
                            break;
                        default:
                            break;
                    }
                }

                var symlist = symbolList.Where(u => (u.LeaderSer == fop.LeaderSer) && (u.LeaderSymbol == lOrder.Symbol) && (u.FollowSer == fa.Ser)).FirstOrDefault();
                if (symlist != null)
                {
                    sym = symlist.FollowSymbol;
                    vo = vo * double.Parse(symlist.SymTrad);
                }


                fOrder = ocFollow.OrderSend(sym, type, vo, price, 10, sl, tp, lOrder.Ticket.ToString() + "|", 0, new DateTime());

                RTicketRecord rtrOpen = new RTicketRecord((ticketList.Count + 1).ToString(), fop.LAcc, fop.LeaderSer, lOrder.Ticket.ToString(), fa.Acc,
                                                fa.Ser, fOrder.Ticket.ToString(), fop.UpDate, DateTime.Now.ToString());
                ticketList.Add(rtrOpen);
                ComMethod.WriteListToIniFile(4, rtrOpen);
                this.Invoke(new Action(() =>
                {
                    log.Add(new Log(DateTime.Now, opDis + ":" + "LO【" + fop.LeaderSer + "-" + lOrder.Ticket + "】FO【" + fa.Ser + "-" + fOrder.Ticket + "】"));
                }));

                break;
            case "PositionClose"://平仓1
            case "PendingClose"://删除挂单 4
            case "PositionModify"://修改2
                                  //根据喊单平台和单号取出跟单的单号列表(不论当前是否策略还在,全部跟单)
                var Tm = ticketList.Where(x => (x.LeaderSer == fop.LeaderSer)
                                                && (x.LeaderTicket == lOrder.Ticket.ToString())
                                                && (x.Des != "PositionModify")
                                                && (x.FollowSer == fa.Ser)
                                                && (x.FollowAcc.ToString() == fa.Acc)).ToList();

                foreach (RTicketRecord t in Tm)
                {
                    fOrder = qcFollow.GetOpenedOrder(int.Parse(t.FollowTicket));//跟单的order
                    if (fOrder != null)
                    {
                        while (qcFollow.GetQuote(lOrder.Symbol) == null)
                            Thread.Sleep(10);

                        //如果订单为 买单 平仓为卖 取卖价 Bid
                        if (fOrder.Type == Op.Buy)
                        {
                            price = qcFollow.GetQuote(lOrder.Symbol).Bid;
                        }
                        //如果订单为 卖单 平仓为买 取买价 Ask
                        if (fOrder.Type == Op.Sell)
                        {
                            price = qcFollow.GetQuote(lOrder.Symbol).Ask;
                        }

                        if (fop.UpDate == "PositionClose")//平买单 
                        {
                            fOrder = ocFollow.OrderClose(lOrder.Symbol, int.Parse(t.FollowTicket), fOrder.Lots, price, 10);
                        }

                        if (fop.UpDate == "PendingClose")//平挂单 
                        {
                            ocFollow.OrderDelete(int.Parse(t.FollowTicket), fOrder.Type, fOrder.Symbol, fOrder.Lots, price);
                        }

                        if (fop.UpDate == "PositionModify")//改单 改止盈止损
                        {
                            fOrder = ocFollow.OrderModify(int.Parse(t.FollowTicket), fOrder.Symbol, fOrder.Type, fOrder.Lots, price,
                                 lOrder.StopLoss, lOrder.TakeProfit, DateTime.Now);
                        }

                        RTicketRecord rtrClose = new RTicketRecord((ticketList.Count + 1).ToString(), fop.LAcc, fop.LeaderSer, lOrder.Ticket.ToString(), fa.Acc,
                                                        fa.Ser, fOrder.Ticket.ToString(), fop.UpDate, DateTime.Now.ToString());
                        ticketList.Add(rtrClose);
                        ComMethod.WriteListToIniFile(4, rtrClose);

                        this.Invoke(new Action(() =>
                        {
                            log.Add(new Log(DateTime.Now, opDis + ":" + "LO【" + fop.LeaderSer + "-" + lOrder.Ticket + "】FO【" + fa.Ser + "-" + fOrder.Ticket + "】"));
                        }));

                    }
                    else
                    {
                        fOrder = new Order();//跟单的order 已平仓
                        fOrder.Ticket = int.Parse(t.FollowTicket);
                    }
                }
                break;
            //case "PendingModify"://修改挂单 5
            //    break;
            //case "PendingFill"://6
            //    break;
            //case "Balance"://7
            //    break;
            //case "Credit"://8
            //    break;
            default:
                break;
        }
    }
    catch (Exception ex)
    {
        this.Invoke(new Action(() =>
        {
            log.Add(new Log(DateTime.Now, opDis + ":【" + fa.Ser + "|"+ fa.Acc + "】" + ex.Message));
        }));
    }
}




0 条评论

发布
问题