vdemydiuk / mtapi

MetaTrader API (terminal bridge)
http://mtapi4.net/
MIT License
522 stars 281 forks source link

IsConnected not working at all #54

Open wqleishen opened 7 years ago

wqleishen commented 7 years ago

1.0.36 when call IsConnected(), there has many seconds with raise a exception!

wqleishen commented 7 years ago

exp.message is "Response from MetaTrader is null" 1.0.35 still has this problem

wqleishen commented 7 years ago

This error occur after the 1.0.32.1 edition! @vdemydiuk

vdemydiuk commented 7 years ago

Function IsConnected is only wrapper over MQL function https://docs.mql4.com/check/isconnected So it has to be used as other mtapi functions that will be performed on MT4 side. Are you using it after or before mtapi client is connected to MT4 ?

wqleishen commented 7 years ago

I using it after mtapi connected to MT4, the IsConnected can't get result and throw exception! I test MQL function IsConnected() in MQL4, it can get the right result! @vdemydiuk

wqleishen commented 7 years ago

I write a monitorex to get all changed orders include modify pending delete orders! but I don know how to use the github...If you have time can add these codes into your project, I already test it works ok! And I checking the logfile's changed to predecide if orders has any change, the old query make too many EA logs; @vdemydiuk

using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Timers; using MtApi;

[Flags]
public enum MonitorEventType
{
    Opened = 0x1,
    Closed = 0x2,
    Changed = 0x4
}

public class OrdersEventArgsEx : EventArgs
{
    public List<MtOrder> this[MonitorEventType _ChangedType_]
    {
        get { return _ChangedOrders[_ChangedType_]; }
    }

    private Dictionary<MonitorEventType, List<MtOrder>> _ChangedOrders =
        new Dictionary<MonitorEventType, List<MtOrder>>
        {
            {MonitorEventType.Opened, new List<MtOrder>()},
            {MonitorEventType.Closed, new List<MtOrder>()},
            {MonitorEventType.Changed, new List<MtOrder>()}
        };

    public Dictionary<MonitorEventType, List<MtOrder>> ChangedOrders => _ChangedOrders;

    public List<MtOrder> AllOrders
    {
        get
        {
            var Orders_ = new List<MtOrder>(_ChangedOrders[MonitorEventType.Opened]);
            Orders_.AddRange(_ChangedOrders[MonitorEventType.Closed]);
            Orders_.AddRange(_ChangedOrders[MonitorEventType.Changed]);

            return Orders_;
        }
    }
}

public class TradeMonitorEx
{
    private readonly Timer _Timer = new Timer();
    private readonly MtApiClient _ApiClient;
    private readonly object _Locker = new object();

    private List<MtOrder> _PreOrders;
    private List<MtOrder> _TempPreOrders;
    private List<MtOrder> _TradeOrders;
    private List<MtOrder> _HistoryOrders;

    private IEnumerable<Int32> _QPreTickets;
    private IEnumerable<Int32> _QTradeTickets;
    private IEnumerable<Int32> _QHistoryTickets;

    private String _LogFilePath;
    private String _LogFileName;
    private long _LogFileLength;

    private MonitorEventType _MonitorEvent;

    public Boolean MonitorOpened => (_MonitorEvent & MonitorEventType.Opened) > 0;
    public Boolean MonitorClosed => (_MonitorEvent & MonitorEventType.Closed) > 0;
    public Boolean MonitorChanged => (_MonitorEvent & MonitorEventType.Changed) > 0;

    private OrdersEventArgsEx _OrderEventArgs = new OrdersEventArgsEx();

    public String LogFilePath
    {
        get { return _LogFilePath; }
        set { _LogFilePath = value; }
    }

    public Int32 MonitorEvent
    {
        get { return (Int32) _MonitorEvent; }
        set { _MonitorEvent = (MonitorEventType) value; }
    }

    public Boolean IsStarted => _Timer.Enabled;
    public event EventHandler<OrdersEventArgsEx> OrdersChanged;
    public Boolean IsMtConnected => _ApiClient.ConnectionState == MtConnectionState.Connected;

    public TradeMonitorEx(MtApiClient _ApiClient_)
    {
        if (_ApiClient_ == null)
            throw new ArgumentNullException(nameof(_ApiClient_));
        _ApiClient = _ApiClient_;

        _MonitorEvent = 0;
        _Timer.Interval = 10000;
        _Timer.Elapsed += TimerElapsed;
    }

    public double Interval
    {
        get { return _Timer.Interval; }
        set { _Timer.Interval = value; }
    }

    public void Start()
    {
        _ApiClient.ConnectionStateChanged += ConnectionStateChanged;

        if (IsMtConnected)
        {
            InitialCheck();
            _Timer.Start();
        }
    }

    public void Stop()
    {
        _ApiClient.ConnectionStateChanged -= ConnectionStateChanged;
        _Timer.Stop();
    }

    private void TryCheckOrders()
    {
        try
        {
            CheckOrders();
        }
        catch (MtConnectionException)
        {
            //TODO: write error to log
        }
        catch (MtExecutionException)
        {
            //TODO: write error to log
        }
    }

    private Boolean LogChanged()
    {
        var LogFileName_ = _LogFilePath + DateTime.Now.ToString("yyyyMMdd") + ".log";
        if (_LogFileName == LogFileName_)
        {
            var LogFile_ = File.Open(
                _LogFileName,
                FileMode.Open,
                FileAccess.Read,
                FileShare.ReadWrite);
            var LogFileLength_ = LogFile_.Length;
            LogFile_.Close();

            if (_LogFileLength == LogFileLength_)
                return false;

            _LogFileLength = LogFileLength_;
        }

        _LogFileName = LogFileName_;
        return true;
    }

    private void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        if (!LogChanged())
            return;

        _Timer.Elapsed -= TimerElapsed;
        TryCheckOrders();
        _Timer.Elapsed += TimerElapsed;
    }

    private Boolean MtOrderEqual(MtOrder _A_, MtOrder _B_)
    {
        return (_A_.OpenPrice == _B_.OpenPrice) &&
            (_A_.TakeProfit == _B_.TakeProfit) &&
            (_A_.StopLoss == _B_.StopLoss) &&
            (_A_.MtExpiration == _B_.MtExpiration);
    }

    private void FindOpenedOrders()
    {
        var QOpenTickets_ = _QTradeTickets.Except(_QPreTickets);
        var QOpenOrders_ = _TradeOrders.Where(Order_ => QOpenTickets_.Contains(Order_.Ticket));

        _OrderEventArgs[MonitorEventType.Opened].AddRange(QOpenOrders_);
    }

    private void RemovePartOpenedOrders()
    {
        var QOpenTimes_ = _OrderEventArgs[MonitorEventType.Opened].Select(
            Order_ => Order_.MtOpenTime);
        var QCloseTimes_ = _OrderEventArgs[MonitorEventType.Closed].Select(
            Order_ => Order_.MtOpenTime);
        var PartCloseTimes_ = QCloseTimes_.Intersect(QOpenTimes_);

        if (!PartCloseTimes_.Any())
            return;

        var PartCloseOrder_ = _OrderEventArgs[MonitorEventType.Opened].Where(
            Order_ => PartCloseTimes_.Contains(Order_.MtOpenTime));

        foreach (var Order_ in PartCloseOrder_.ToList())
        {
            var CloseOrder_ = _OrderEventArgs[MonitorEventType.Closed].FirstOrDefault(
                MatchOrder_ => MatchOrder_.MtOpenTime == Order_.MtOpenTime);
            if (CloseOrder_ == null)
                continue;

            CloseOrder_.TakeProfit = CloseOrder_.Lots/(CloseOrder_.Lots + Order_.Lots);
            CloseOrder_.TakeProfit = Math.Round(CloseOrder_.TakeProfit, 2);
            _OrderEventArgs[MonitorEventType.Opened].Remove(Order_);
        }
    }

    private void FindChangedOrders()
    {
        var QChangeTickets_ = _QTradeTickets.Intersect(_QPreTickets);
        var PreOrders_ = _TempPreOrders.Where(Order_ =>
            QChangeTickets_.Contains(Order_.Ticket)).ToDictionary(Order_ => Order_.Ticket);
        var TradeOrders_ = _TradeOrders.Where(Order_ =>
            QChangeTickets_.Contains(Order_.Ticket)).ToDictionary(Order_ => Order_.Ticket);

        _OrderEventArgs[MonitorEventType.Changed].AddRange(
            TradeOrders_.Where(Order_ =>
            {
                if (!PreOrders_.ContainsKey(Order_.Key))
                    return false;
                return !MtOrderEqual(Order_.Value, PreOrders_[Order_.Key]);
            }).Select(Order_ => Order_.Value));
    }

    private void FindClosedOrders()
    {
        var QPreCloseTickets_ = _QPreTickets.Except(_QTradeTickets);
        if (QPreCloseTickets_.Any())
        {
            _HistoryOrders = _ApiClient.GetOrders(OrderSelectSource.MODE_HISTORY);
            _QHistoryTickets = _HistoryOrders.Select(Order_ => Order_.Ticket);

            var QCloseTickets_ = _QHistoryTickets.Intersect(QPreCloseTickets_);
            _OrderEventArgs[MonitorEventType.Closed].AddRange(
                _HistoryOrders.Where(Order_ => QCloseTickets_.Contains(Order_.Ticket)));
            foreach (var Order_ in _OrderEventArgs[MonitorEventType.Closed])
                Order_.TakeProfit = 1.0;
        }
    }

    private void CheckOrders()
    {
        _OrderEventArgs[MonitorEventType.Opened].Clear();
        _OrderEventArgs[MonitorEventType.Changed].Clear();
        _OrderEventArgs[MonitorEventType.Closed].Clear();
        _TradeOrders = _ApiClient.GetOrders(OrderSelectSource.MODE_TRADES);

        lock (_Locker)
            _TempPreOrders = _PreOrders;

        if (_TempPreOrders != null)
        {
            _QPreTickets = _TempPreOrders.Select(Order_ => Order_.Ticket);
            _QTradeTickets = _TradeOrders.Select(Order_ => Order_.Ticket);

            if (MonitorOpened) FindOpenedOrders();
            if (MonitorClosed) FindClosedOrders();
            if (MonitorChanged) FindChangedOrders();

            RemovePartOpenedOrders();
        }

        lock (_Locker)
            _PreOrders = _TradeOrders;

        if (((_OrderEventArgs[MonitorEventType.Opened].Count > 0) && MonitorOpened) ||
            ((_OrderEventArgs[MonitorEventType.Closed].Count > 0) && MonitorClosed) ||
            ((_OrderEventArgs[MonitorEventType.Changed].Count > 0) && MonitorChanged))
            OrdersChanged?.Invoke(this, _OrderEventArgs);
    }

    private void OnMtConnected()
    {
    }

    private void OnMtDisconnected()
    {
    }

    private void ConnectionStateChanged(object sender, MtConnectionEventArgs e)
    {
        switch (e.Status)
        {
            case MtConnectionState.Connected:
                InitialCheck();
                OnMtConnected();
                break;
            case MtConnectionState.Failed:
            case MtConnectionState.Disconnected:
                OnMtDisconnected();
                break;
        }
    }

    private void InitialCheck()
    {
        lock (_Locker)
            _PreOrders = null;

        foreach (var Orders_ in _OrderEventArgs.ChangedOrders)
            Orders_.Value.Clear();

        Task.Factory.StartNew(TryCheckOrders);
    }
}
vdemydiuk commented 7 years ago

Can you show me source code where you are using function IsConnected? It is very strange that you have got exception while using this function. It is working good in my test application. Can you also try to use test application and say what is the result?

HengzheLi commented 6 years ago

just for your reference, I was encountered the same issue under win7 and my mt4 install in system folder. Then I run MT4 as administrator, solve it.

Hope this help

alexssource commented 6 years ago

Hi @vdemydiuk! I also expected the same problem when using program in Strategy Tester (MT4). The error is occurred when using almost all functions communicated with terminal like IsConnected, IsTesting, SendOrder and so on. I recorded a video illustrates the bug, please see https://yadi.sk/i/UpWPNvaRqRaLtw I use virtual machine for testing: 1xIntel Core i7, 4Gb RAM