<?php
class JSONObject {
    public function __construct($json = false) {
        if ($json) $this->set(json_decode($json, true));
    }
    public function set($data) {
        foreach ($data AS $key => $value) {
            if (is_array($value)) {
                $sub = new JSONObject;
                $sub->set($value);
                $value = $sub;
            }
            $this->{$key} = $value;
        }
    }
}
class MT4API
{
    public function __construct($apiUser, $apiPass)
    {
        $this->auth = true;
        $this->addr = "rest.mtapi.online";
        if($this->auth)
        {
            $url = "http://".$this->addr."/token?username=${apiUser}&password=${apiPass}";
            $options = array(
                'http' => array(
                    'header'  => "Content-type: application/json".PHP_EOL,
                    'method'  => 'POST',
                    'content' => 'content'
                )
            );
            $context  = stream_context_create($options);
            $jsonString = file_get_contents($url, false, $context);
            $res = new JSONObject($jsonString);
            $this->token = $res->access_token;
        }
    }
    private function GetContext()
    {
        if($this->auth)
            $options = array(
                'http' => array(
                    'header'  => "Content-type: application/x-www-form-urlencoded".PHP_EOL
                                ."Authorization: Bearer ".$this->token,
                    'method'  => 'GET'
                )
                );
        else
            $options = array(
                'http' => array(
                    'header'  => "Content-type: application/x-www-form-urlencoded".PHP_EOL,
                    'method'  => 'GET'
                )
                );
        return stream_context_create($options);
    }
    private function GetResult($url, $connect = false)
    {
        $jsonString = file_get_contents($url, false, $this->GetContext());
        $res = new JSONObject($jsonString);
        if($res->code == "OK")
        {
            if($connect)
                $this->id = $res->login_id;
            return $res->data;
        }
        else
            throw new Exception($res->message);
    }
    public function Connect($user, $pass, $host, $port)
    {
        return $this->GetResult("http://".$this->addr."/mt4/new?user=${user}&password=${pass}"
                        ."&host=${host}&port=${port}", true);
    }
    public function GetQuote($symbol)
    {
        return $this->GetResult("http://".$this->addr."/mt4/quote?id=".$this->id."&symbol=${symbol}");
    }
    public function OrderSend($symbol, $price, $volume, $operation)
    {
        return $this->GetResult("http://".$this->addr."/mt4/ordersend?id=".$this->id."&symbol=${symbol}"
            ."&operation=${operation}&volume=${volume}&price=${price}&slippage=0"
            ."&stoploss=0.0&takeprofit=0.0&comment=");
    }
}
class AsyncOrderSend extends Thread
{
    public function __construct($api, $symbol, $price, $volume, $operartion)
    {
        $this->api = $api;
        $this->symbol = $symbol;
        $this->price = $price;
        $this->volume = $volume;
        $this->operartion = $operartion;
        $this->done = false;
    }
    public function run()
    {
        $this->result = $this->api->OrderSend($this->symbol, $this->price, $this->volume, $this->operartion);
        $this->done = true;
    }
}
function millitime() {
    $microtime = microtime();
    $comps = explode(' ', $microtime);
    // Note: Using a string here to prevent loss of precision
    // in case of "overflow" (PHP converts it to a double)
    return sprintf('%d%03d', $comps[1], $comps[0] * 1000);
}
$symbol = "BTCUSD";
$apiMaster = new MT4API("DemoLogin2", "DemoLoginPassword2");
//call connect at the beginning, in this case API establish connection with MT4 Server
$apiMaster->Connect(33350, "artur.", "demo4newyork.evolve.markets", 443);
//call getquote at the beginning in this case, API subscribes to the symbol, and all further $apiMaster->getquote calls would be fast
echo "Master connected".PHP_EOL;
$apiMaster->GetQuote($symbol);
$apiSlave1 = new MT4API("DemoLogin2", "DemoLoginPassword2");
$apiSlave1->Connect(33351, "artur.", "demo4newyork.evolve.markets", 443); //call connect before copy
echo "Slave1 connected".PHP_EOL;
$apiSlave2 = new MT4API("DemoLogin2", "DemoLoginPassword2");
$apiSlave2->Connect(33352, "artur.", "demo4newyork.evolve.markets", 443); //call connect before copy
echo "Slave2 connected".PHP_EOL;
//multithreaiding copy below
//all APIs connected, we already made first call of $apiMaster->getquote,
// so it would be everything fast now
echo "Start    ".millitime().PHP_EOL;
$ask = $apiMaster->GetQuote($symbol)->ask;
$thread1 = new AsyncOrderSend($apiSlave1, $symbol, $ask, 0.01, "Buy");
$thread1->start();
echo "1st sent ".millitime().PHP_EOL;
$thread2 = new AsyncOrderSend($apiSlave2, $symbol, $ask, 0.01, "Buy");
$thread2->start();
echo "2nd sent ".millitime().PHP_EOL;
//while(!$thread1->done);
//while(!$thread2->done);
//echo "Executed ".millitime().PHP_EOL;
?>