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

发布于 2019-12-27 21:53:59

        Easy way to build mechanical trading systems in Java or C#(NJ4X)

NJ4X是一个俄罗斯哥们写的,其初衷是打破单机运行32MT4终端限制,摆脱语言和终端数量限制。其原理是修改注册表中的多用户登录和用户桌面共享内存来实现。简单就是单个用户有32的限制,但100个用户同时登录就是3200个终端,不得不说这在当时是一种超好的思路。

图片1.png

(NJ4X使用流程图)

简单介绍下NJ4X,他包括2部分,终端服务器和库(或jar包),而终端服务器说白了就是MT4终端的集合,至于库或者jar包是终端服务器的接口文件。

 图片2.png

(终端服务器v2.8.3

Ok,言归正传,本文介绍的是跨平台跟单,如有时间我会写一篇详细的NJ4X的介绍。

首先,同EA跟单一样,有信号源账号和跟单账号,信号源设置监听器,发现订单改变,获取订单复制即可。DEMO代码如下:

import com.jfx.*;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CopierDemo {

    public static final String TerminalHost = "localhost";
    public static final int TerminalPort = 7788;
    public static final String
            MasterBroker = "MIGBank-Demo";
    public static final String
            CopierBroker = "MIGBank-Demo";

    public static final String
            MasterAccount = "1218296449";
    public static final String
            MasterPassword = "os1brmp";
    public static final String
            CopierAccount = "1218296450";
    public static final String
            CopierPassword = "sya8ltw";
    public static void main(String[] args) {
        try {
            Master master = new Master(MasterAccount, MasterPassword, MasterBroker);
            Copier slave = new Copier(CopierAccount, CopierPassword, CopierBroker);
            master.AddSlave(slave);
            while (true) {
                Thread.sleep(100000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

@SuppressWarnings("deprecation")
class Copier extends Strategy {
    private static final Logger LOGGER = Logger.getLogger(Copier.class);
    private final String acc;
    private final String broker;
    private final Hashtable<Long, Integer> _ordersMap;
    private final String password;
    private Master master;

    public Copier(String acc, String password, String broker) throws IOException {
        this.acc = acc;
        this.password = password;
        this.broker = broker;
        _ordersMap = new Hashtable<>();
        connect(CopierDemo.TerminalHost, CopierDemo.TerminalPort, new Broker(this.broker), this.acc, this.password);
        info("Slave connected");
    }

    private void info(String msg) {
        LOGGER.info(acc + "@" + broker + "> " + msg);
    }
    @Override
    public synchronized void init(String symbol, int period) {
        super.init(symbol, period);
        int ordersTotal = ordersTotal();
        for (int i = 0; i < ordersTotal; i++) {
            OrderInfo order = orderGet(i, SelectionType.SELECT_BY_POS, SelectionPool.MODE_TRADES);
            if (order != null) {
                if (order.getMagic() != 0) {
                    _ordersMap.put(
                            order.getMagic(),
                            order.getTicket()
                    );
                    info(String.format("Master order %d is mapped to %s", order.getMagic(), "" + order));
                } else {
                    info(String.format("Custom order %s left un-managed", "" + order));
                }
            }
        }
    }

    void setMaster(Object master) throws MT4Exception {
        this.master = (Master) master;
        info(String.format("Attached to %s", this.master.Acc + "@" + this.master.Broker));
        //
        PositionInfo positionInfo = this.master.PositionInfo;
        for (OrderInfo masterOrder : positionInfo.historicalOrders().values()) {
            MasterOrderClosedOrDeleted(masterOrder);
        }
    }

    void MasterOrderClosedOrDeleted(OrderInfo masterOrder) throws ErrUnknownSymbol, ErrNoOrderSelected {
        if (_ordersMap.containsKey(masterOrder.getTicket())) {
            int orderTicket = _ordersMap.get(masterOrder.getTicket());
            OrderInfo order = orderGet(orderTicket, SelectionType.SELECT_BY_TICKET, SelectionPool.MODE_TRADES);
            if (order != null) {
                if (CloseOrder(order)) {
                    _ordersMap.remove(masterOrder.getTicket());
                }
            } else {
                info(String.format("Order %d not found", orderTicket));
                _ordersMap.remove(masterOrder.getTicket());
            }
        }
    }

    private boolean CloseOrder(OrderInfo order) throws ErrUnknownSymbol, ErrNoOrderSelected {
        TradeOperation orderType = order.getType();
        switch (orderType.val) {
            case TradeOperation._OP_BUY:
            case TradeOperation._OP_SELL:
                try {
                    if (orderClose(order.getTicket(), orderLots(),
                            marketInfo(symbol(),
                                    orderType.val == TradeOperation._OP_BUY
                                            ? MarketInfo.MODE_BID
                                            : MarketInfo.MODE_ASK),
                            5, 0)) {
                        info(String.format("Order %s has been closed", order.toString()));
                        return true;
                    }
                } catch (MT4Exception err) {
                    err.printStackTrace();
                }
                info(String.format("Order %s to be closed; todo", order.toString()));
                return false;
            default:
                try {
                    if (orderDelete(order.getTicket(), Color.Black.val)) {
                        info(String.format("Order %s has been deleted", order.toString()));
                        return true;
                    }
                } catch (MT4Exception err) {
                    err.printStackTrace();
                }
                info(String.format("Can not delete order %s", order.toString()));
                return false;
        }
    }

    void MasterOrderCreated(OrderInfo masterOrder) {
        try {
            Date exp = masterOrder.getExpiration();
            int ticket = orderSend(
                    masterOrder.getSymbol(),
                    masterOrder.getType(),
                    masterOrder.getLots(),
                    masterOrder.getOpenPrice(), 
                    5,
                    masterOrder.getSl(),
                    masterOrder.getTp(),
                    master.Acc + "@" + master.Broker,
                    masterOrder.getTicket(),
                    exp == null || exp.getTime() == 0 ? null : exp,
                    0
            );
            if (ticket != 0) {
                _ordersMap.put(masterOrder.ticket(), ticket);
                info(String.format("Master order %s is mapped to %d", masterOrder.toString(), ticket));
            }
        } catch (MT4Exception err) {
            err.printStackTrace();
        }
    }
    public void OnChange(PositionChangeInfo masterPositionChanges) throws MT4Exception {
        PositionChangeInfo changes = masterPositionChanges;
        for (OrderInfo o : changes.getNewOrders()) {
            LOGGER.info("NEW: " + o);
            MasterOrderCreated(o);
        }
        for (OrderInfo o : changes.getModifiedOrders()) {
            LOGGER.info("MODIFIED: " + o);
        }
        for (OrderInfo o : changes.getClosedOrders()) {
            LOGGER.info("CLOSED: " + o);
            MasterOrderClosedOrDeleted(o);
        }
        for (OrderInfo o : changes.getDeletedOrders()) {
            LOGGER.info("DELETED: " + o);
            MasterOrderClosedOrDeleted(o);
        }
    }
}

class Master extends Strategy {
    private final static ExecutorService threadPool = Executors.newCachedThreadPool();
    private static final Logger LOGGER = Logger.getLogger(Master.class);
    //
    final String Acc;
    final String Broker;
    final String Passwd;
    final ArrayList<Copier> Slaves;

    PositionInfo PositionInfo;
    public Master(String acc, String passwd, String broker) throws IOException {
        Acc = acc;
        Passwd = passwd;
        Broker = broker;
        Slaves = new ArrayList<>();
        setPositionListener(
                new PositionListener() {
                    @Override
                    public void onInit(PositionInfo info) {
                        PositionInfo = info;
                    }

                    @Override
                    public void onChange(PositionInfo info, final PositionChangeInfo changes) {
                        for (final Copier c : Slaves) {
                            threadPool.submit(new Runnable() {
                                @Override
                                public void run() {
                                    try {
                                        c.OnChange(changes);
                                    } catch (MT4Exception err) {
                                        err.printStackTrace();
                                    }
                                }
                            });
                        }
                    }
                }
        );
        connect(CopierDemo.TerminalHost, CopierDemo.TerminalPort, new Broker(Broker), Acc, Passwd);
        //
        info("Master connected");
    }

    private void info(String msg) {
        LOGGER.info(Acc + "@" + Broker + "> " + msg);
    }
	
    public void AddSlave(final Copier copier) {
        Slaves.add(copier);
        threadPool.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    copier.setMaster(Master.this);
                } catch (MT4Exception err) {
                    err.printStackTrace();
                }
            }
        });
    }
}

当然,NJ4X虽然对于MQL来说有很大进步,但是相对于clientapi和managerapi来说需要更多的资源(实测4核8G的服务器也仅仅能跑150个终端左右)

0 条评论

发布
问题