本文旨在说明,通过一个实际的例子,您如何将 MetaTrader 5 终端与外部 Web 服务通信。我们发布的交易信号是由一款 EA生成。
此想法来自于自动交易的特定概念,称为电脑辅助交易。概括地讲,二十一世纪的计算机没有认知能力,但它们都非常善于处理信息和执行数据。那么,为何我们不建立一套计算机系统,使用人类大脑作为过滤器,来进行决策呢?这种方式的灵感建立在 Human-based computation(以人为本的计算) (HBC) 模式,因此,应该重点建立决策支持工具,而非进行决策者算法编码。
我最初想要创建一个 RSS 来推送我的 EA 生成的交易信号(假定有一个中线或长线的底层交易系统,这个想法对于自动剥头皮系统无效)。一个访问推送内容的人可以根据当下情况,在信号到达市场之前验证我的自动交易信号。不过,我很快意识到,一切都可以更加社交化,并自思“为什么不在 Twitter (推特)上发布我的交易信号?”这促使我开发这个社交决策支持系统。
图例 1. SDSS 体系结构
顺便说一句,如果您打算创建一个与外汇交易相关的技术创新,那这篇文章可以帮助您找到一些思路。它可以被看作是一个技术指南,用于建立一个基于 SDSS 的商业 SaaS(软件即服务)。
这段文字很长,所以我决定把它分成两部分。第一部分关注点是 Web 服务体系结构,MetaTrader 5 终端和 Twitter(推特) 应用程序之间的通信协议,以及 Web 应用程序与 Twitter(推特)的最终集成。第二部分将覆盖如上所示网络图中的 MQL5 层面,其目的是使用我们的社交决策支持系统的 RESTful web 服务。具体来说,我们将采用文章 MQL5-RPC. Remote Procedure Calls from MQL5: Web Service Access and XML-RPC ATC Analyzer for Fun and Profit(MQL5-RPC 来自 MQL5 的远程过程调用:针对乐趣及获利的网络服务访问及 XML-RPC 自动交易锦标赛分析程序) 中的相同方式编写一个 MQL5-RESTful 框架代码。
这篇文章也是社交化的,所以我鼓励您发表您的意见,以帮助继续进行第二部分。
1.1. 服务器上的 MetaTrader 5
这个 MetaTrader 5 终端运行在全天 24 小时工作的机器上。这台电脑可以是虚拟专用服务器 (VPS) 或一台专用服务器 (DS)。服务器上的 MetaTrader 5 与 Twitter(推特)应用之间的通信则是通过 RESTful web 服务。数据交换格式为 JSON。在本文的第二部分,我们将部署 MQL5 层来使用根据本文后面所定义的通信协议 Web 服务。
1.2. Twitter 应用
如我们在介绍中所述, 我们正在开发本文第一部分中的采用 SDSS 的 Twitter 应用。这是一个 PHP web 应用,它基本上是接收 MetaTrader 5 终端的信号,将它们保存在 MySQL 数据库中,并随后发布。但是,这个应用可以扩展,以便处理需要人工能力解决的很多问题。
例如,你想获取知识,并建立一个 web 本体 接收经过人工过滤的,来自 '服务器上的 MetaTrader 5' 的信号,并从人工角度看看 EA 信号的可靠性如何。我们可以计算出与之相关的给定信号的可靠性。这仅仅是一个想法,并未包括在本文中,当然,它在理论上是可行的。这仅仅是一个基于以人为本的计算(HBC)模式的实际应用。
1.3. Twitter(推特)
如 Wikipedia 所述, Twitter(推特) 是著名的在线社交网络和微博服务,它允许用户发送并读取 140 个字符的短文本消息, 称为 tweets(发布)。
2.1. REST 概览
REST, SOAP 和 XML-RPC 是三种常用架构范式,用于建立 web 服务。由于大多数现代 Web 2.0 应用使用此模式来开发自己的业务, 我们也将在 REST 基础上编写我们的 SDSS。我鼓励您阅读题为 The Twitter REST API 的文档,了解更多有关这个话题的内容。总之, REST 调用 HTTP 进行交换,并使用 JSON 或 XML 作为数据交换格式。
不像 SOAP 和 XML-RPC, REST 可以十分容易实现,并且也很快速。它最简单是因为没有如同 XML-RPC 和 SOAP 中那样的协议规范。这意味着开发人员不得不学习 XML 伪语言的一切以便部署 web 服务。另一方面, REST 在客户端与服务器之间可以使用 JSON 作为数据交换格式, 这样可以获得更快速的响应。事实上,在 JSON 中描述对象,其占用的字节数总是比 XML 的更少。这是因为 JSON 语义更多,或换一种说法,用 JSON 表示信息比用 XML 所需语法元素较少。
2.2. SDSS API 参考
您是否已经读过题为 The Twitter REST API 的文档?现在,综合所有说法,Twitter 的 API 规范可以作为我们构建 SDSS API 的借鉴。回想一下,我们正做的事情非常简单,因为这篇文章的目的不是开发完整的 SDSS,而是可以被部署的技术创新,但在现实中表现为一个实际应用,即可以将您的 MetaTrader 5 终端与外部 web 服务连接。据此,在本节中,我们将设计一个极其简单的 API,它以单独的 REST 方法使用 HTTP 的 POST。它用于接收,存储到数据库中,并发布一个特定 EA 的交易信号。
2.2.1. 常规
该 API 将接管 http://api.sdss-your-startup.com,并可通过 HTTP 或 HTTPS 访问。对于 POST 请求, 参数会以 JSON 格式随 POST 实体提交。
2.2.2. REST 资源
资源 | URL | 描述 |
---|---|---|
POST 信号/添加 | http://api.sdss-your-startup.com /signal/add | 发送一个 EA 信号至 Twitter 应用程序。这个请求由 MetaTrader 5 终端执行,以便 SDSS 存储和发布交易信号。 |
正如介绍中指明的,本文是社交化的, 所以我鼓励您在此列出您的社交决策支持系统所期望实现的 REST 方法。请随意发表您的意见,并在 MQL5 社区分享。
2.2.3. POST 信号/添加
参数 | 描述 |
---|---|
ea_id |
此 ID 是发送新信号的 EA 标识符。示例值: 12345 |
symbol |
交易品种符号。示例值: EURUSD |
opeartion |
所执行的操作。示例值: BUY 或 SELL |
value |
交易品种价位。示例值: 1.3214 |
请求示例:
{ "ea_id": 1, "symbol": "AUDUSD", "operation": "BUY", "value": 0.9281 }
在所示例子中, 有两个要点。一方面,我们假设同一时刻,只有一个 MetaTrader 5 终端发送信号到 Twitter 应用。出于这个原因,不需要终端 ID。如果再之后,我们决定扩展该系统,并进一步开发我们的创新应用,我们可能要连接多个终端至 Twitter 应用程序。
因此,在这种情况下,我们会添加一个名为 mt5_id 的字段来标识 MetaTrader 5 终端。另一方面, 注意以上调用应该经过某些安全认证机制 (Basic HTTP Authentication(基本 HTTP 认证)附加在 SSL, 基于认证的令牌或 OAuth)。尽管我们跳过了这个部分,但不能忘记指出这个问题。请注意,若在 MetaTrader 5 终端和 Twitter 应用之间没有认证机制,所有人都会知道图例 1 中发送交易信号至 Twitter 应用的通信协议。SDSS 体系结构。
该 REST API 规范帮助我们看清系统如何工作, 所以我们现在能够理解数据库设计了:
# MySQL database creation... CREATE DATABASE IF NOT EXISTS sdss; use sdss; # Please, change the user's password in production GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, LOCK TABLES, CREATE TEMPORARY TABLES ON `sdss`.* TO 'laplacianlab'@'localhost' IDENTIFIED BY 'password'; CREATE TABLE IF NOT EXISTS eas ( id mediumint UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(32), description TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINE=InnoDB; CREATE TABLE IF NOT EXISTS signals ( id int UNSIGNED NOT NULL AUTO_INCREMENT, id_ea mediumint UNSIGNED NOT NULL, symbol VARCHAR(10) NOT NULL, operation VARCHAR(6) NOT NULL, value DECIMAL(9,5) NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), FOREIGN KEY (id_ea) REFERENCES eas(id) ) ENGINE=InnoDB; # Dump some sample data... INSERT INTO eas(name, description) VALUES ('Bollinger Bands', '<p>Robot based on Bollinger Bands. Works with H4 charts.</p>'), ('Two EMA', '<p>Robot based on the crossing of two MA. Works with H4 charts.</p>');
用开发者自己的话来说, Slim(瘦) 是一个 PHP 微框架,可以帮助您快速书写简洁但强力的 web 应用和 API。是的, 您猜对了!我们就基于 Slim 书写我们的 RESTful API, 只需很少的几行代码。请记住,出于学习原因以及简单化,我们只编写一个 HTTP POST 方法。请阅读 Slim 的官方文档,详细了解它是如何工作的。
图例 2. 基于 Slim 的 PHP API 目录结构
config\config.php
<?php // Creating constants. // General define('BASE_URL', 'laplacianlab.local'); define('APPLICATION_PATH', realpath(dirname(__FILE__)) . '/../'); // Database connection define('DB_NAME', 'sdss'); define('DB_USER', 'laplacianlab'); define('DB_PASSWORD', 'password'); // Don't forget to change this in your production server! define('DB_SERVER', 'localhost');
model\DBConnection.php
<?php class DBConnection { private static $instance; private $mysqli; private function __construct() { $this->mysqli = new MySQLI(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME); } public static function getInstance() { if (!self::$instance instanceof self) self::$instance = new self; return self::$instance; } public function getHandler() { return $this->mysqli; } }
public\.htaccess
<IfModule mod_rewrite.c> <IfModule mod_negotiation.c> Options -MultiViews </IfModule> RewriteEngine On # Redirect Trailing Slashes... RewriteRule ^(.*)/$ /$1 [L,R=301] # Handle Front Controller... RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [L] </IfModule>
public\index.php
<?php // Bootstrap logic require_once '../config/config.php'; set_include_path(get_include_path() . PATH_SEPARATOR . APPLICATION_PATH . '/vendor/'); set_include_path(get_include_path() . PATH_SEPARATOR . APPLICATION_PATH . '/model/'); require_once 'slim/slim/Slim/Slim.php'; require_once 'DBConnection.php'; use \Slim\Slim; Slim::registerAutoloader(); $app = new Slim(); $app->response->headers->set('Content-Type', 'application/json'); // RESTful API methods // POST signal/add $app->post('/signal/add', function() { $request = Slim::getInstance()->request(); $signal = json_decode($request->getBody()); $sql = 'INSERT INTO signals(id_ea, symbol, operation, value) VALUES (' . mysql_real_escape_string($signal->ea_id) . ",'" . mysql_real_escape_string($signal->symbol) . "','" . mysql_real_escape_string($signal->operation) . "'," . mysql_real_escape_string($signal->value) . ')'; DBConnection::getInstance()->getHandler()->query($sql); $signal->id = DBConnection::getInstance()->getHandler()->insert_id; echo json_encode($signal); }); // More API methods here!.., according to your API spec $app->run();
composer.json
{ "require": { "slim/slim": "2.*", "abraham/twitteroauth": "dev-master" } }
有了这一切,我们可以在本地开发机器上测试 Web 服务。顺便说一句,不要忘了(1) 在您 hosts 文件里添加一个新条目,以便您的 Windows 能够解析本地域名 api.laplacianlab.local,以及(2) 为您的 Apache 创建一个新的虚拟主机。
C:\Windows\System32\Drivers\etc\hosts
::1 localhost # Copyright (c) 1993-2009 Microsoft Corp. # # This is a sample HOSTS file used by Microsoft TCP/IP for Windows. # # This file contains the mappings of IP addresses to host names. Each # entry should be kept on an individual line. The IP address should # be placed in the first column followed by the corresponding host name. # The IP address and the host name should be separated by at least one # space. # # Additionally, comments (such as these) may be inserted on individual # lines or following the machine name denoted by a '#' symbol. # # For example: # # 102.54.94.97 rhino.acme.com # source server # 38.25.63.10 x.acme.com # x client host # localhost name resolution is handled within DNS itself. # 127.0.0.1 localhost # ::1 localhost 127.0.0.1 localhost 127.0.0.1 api.laplacianlab.local
httpd-vhosts.conf
# Virtual Hosts # # Required modules: mod_log_config # If you want to maintain multiple domains/hostnames on your # machine you can setup VirtualHost containers for them. Most configurations # use only name-based virtual hosts so the server doesn't need to worry about # IP addresses. This is indicated by the asterisks in the directives below. # # Please see the documentation at # <URL:http://httpd.apache.org/docs/2.4/vhosts/> # for further details before you try to setup virtual hosts. # # You may use the command line option '-S' to verify your virtual host # configuration. # # VirtualHost example: # Almost any Apache directive may go into a VirtualHost container. # The first VirtualHost section is used for all requests that do not # match a ServerName or ServerAlias in any <VirtualHost> block. # <VirtualHost *:80> ServerAdmin webmaster@laplacianlab.local DocumentRoot "c:/wamp/www/laplacianlab/public" ServerName api.laplacianlab.local ErrorLog "logs/api.laplacianlab.local-error.log" CustomLog "logs/api.laplacianlab.local-access.log" common <directory "c:/wamp/www/laplacianlab/public"> Options FollowSymLinks AllowOverride all Order Deny,Allow Deny from all Allow from 127.0.0.1 </directory> </VirtualHost>现在我们开始用 RESTClient 测试第一个 REST 资源, 它是一个 Firefox 补丁用于调试 RESTful web 服务。如果一切正常,web 服务必须运行我们的 Slim 方法,并且返回一个 HTTP 200 的结果以及 JSON 响应。
图例 3. 发送一个 POST 信号/添加请求至 http://api.laplacianlab.local
则 HTTP 响应 POST 信号/添加请求的头部如下:
Status Code: 200 OK Connection: Keep-Alive Content-Length: 70 Content-Type: application/json Date: Mon, 07 Apr 2014 18:12:34 GMT Keep-Alive: timeout=5, max=100 Server: Apache/2.4.4 (Win64) PHP/5.4.12 X-Powered-By: PHP/5.4.12
以及 HTTP 响应实体:
{ "ea_id": 1, "symbol": "AUDUSD", "operation": "BUY", "value": 0.9281, "id": 22 }
我们得到它了!我们已经实现了社交决策支持系统的一部分,响应的图例如下。 但是记住, 在实际场景中要有认证层来保护调用。
图例 4. MetaTrader 5 和 Twitter 应用通过 RESTful web 服务彼此对话
现在让我们来处理网络图中从瘦 PHP Twitter 应用发布交易信号到 Twitter 的部分。
图例 5. 从 Twitter 应用发布交易信号到 Twitter
下一步是什么?你再次猜对了!首先,您需要一个 Twitter 应用。所以,请去 Twitter 开发者网站, 用您的 Twitter 帐户登录 (您首先要有一个 Twitter 帐户,以便您创建 Twitter 应用), 进入 "我的应用" 并点击 "创建新应用"。
图例 6. 在 Twitter 开发者中创建一个新应用
您需要填写您的新应用的详细信息并接受开发者之路的规则。例如, 我的新应用详情如下:
名称: Laplacianlab's SDSS
描述: Social Decision Support System
网站: http://api.laplacianlab.local
回调 URL: http://api.laplacianlab.local/twitter/oauth_callback
现在请进入标签名为 "权限" 的页面并且更改权限为 "读和写"。最后,当您创建 Twitter 应用程序之后,写下您的 API 密钥,您的 API 密钥和您的 Oauth 回调 URL,以便您可以将它们作为常量在您的 config\ config.php 文件中使用:
// Twitter OAuth define('API_KEY', 'akMnfXR45MkoaWbZoPiu3'); define('API_SECRET', '45Mkoa54NcvQRBbf119qWerty0DnIW45MncvFgqw'); define('OAUTH_CALLBACK', 'http://api.laplacianlab.local/twitter/oauth_callback');
在这一点我们使用 Laplacianlab 的 SDSS 与 瘦 PHP 微应用通信 (即我们之前创建的 Twitter 应用)。要做到这一点,你需要知道 OAuth 2.0 协议 的基本知识,请不要错过阅读官方文档的机会。您应该很熟悉 OAuth 的流程图。
图例 7. OAuth 流程图
于是,根据这张图,我们现在必须创建以下 MySQL 数据表来存储资源拥有者(想发布交易信号的推友):
CREATE TABLE IF NOT EXISTS twitterers ( id mediumint UNSIGNED NOT NULL AUTO_INCREMENT, twitter_id VARCHAR(255), access_token TEXT, access_token_secret TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINE=InnoDB;
具体来说,我们使用 TwitterOAuth,它是一个配合 Twitter 的 OAuth API 工作的 PHP 库。如果您是通过 Composer,并使用我在之前章节附带的 composer.json 文件来安装 Slim,则您不必担心安装该库文件,因为 TwitterOAuth 已经复制到您的 PHP 应用供应商文件夹。
否则,您可以从 GitHub 下载这个 PHP 控件。以 OAuth 流程为鉴, 我们只需要为 tweeterers 方法编程来申请 Laplacianlab 的 SDSS 权限,以及 oauth 回调。鉴于我们的 SDSS 现在是如此简单,我们可以在 index.php 文件里写进所有内容。
public\index.php
<?php // Bootstrap logic require_once '../config/config.php'; set_include_path(get_include_path() . PATH_SEPARATOR . APPLICATION_PATH . '/vendor/'); set_include_path(get_include_path() . PATH_SEPARATOR . APPLICATION_PATH . '/model/'); require_once 'slim/slim/Slim/Slim.php'; require_once 'abraham/twitteroauth/twitteroauth/twitteroauth.php'; require_once 'DBConnection.php'; use \Slim\Slim; session_start(); Slim::registerAutoloader(); $app = new Slim(); $app->response->headers->set('Content-Type', 'application/json'); // RESTful API methods // POST signal/add $app->post('/signal/add', function() { $request = Slim::getInstance()->request(); $signal = json_decode($request->getBody()); $sql = 'INSERT INTO signals(id_ea, symbol, operation, value) VALUES (' . mysql_real_escape_string($signal->ea_id) . ",'" . mysql_real_escape_string($signal->symbol) . "','" . mysql_real_escape_string($signal->operation) . "'," . mysql_real_escape_string($signal->value) . ')'; DBConnection::getInstance()->getHandler()->query($sql); $signal->id = DBConnection::getInstance()->getHandler()->insert_id; echo json_encode($signal); }); // More API methods here!.., according to your API spec // Twitter OAuth flow // This method is for users to give permissions to Laplacianlab's SDSS to tweet // on their behalf. $app->get('/tweet-signals', function() use ($app) { if (empty($_SESSION['twitter']['access_token']) || empty($_SESSION['twitter']['access_token_secret'])) { $connection = new TwitterOAuth(API_KEY, API_SECRET); $request_token = $connection->getRequestToken(OAUTH_CALLBACK); if ($request_token) { $_SESSION['twitter'] = array( 'request_token' => $request_token['oauth_token'], 'request_token_secret' => $request_token['oauth_token_secret'] ); switch ($connection->http_code) { case 200: $url = $connection->getAuthorizeURL($request_token['oauth_token']); // redirect to Twitter $app->redirect($url); break; default: echo '{"error":{"text":"Connection with Twitter failed"}}'; break; } } else { echo '{"error":{"text":"Error Receiving Request Token"}}'; } } else { echo '{"message":{"text":"Everything is ok! Laplacianlab\'s SDSS ' . 'can now tweet trading signals on your behalf. Please, if you no ' . 'longer want the SDSS to tweet on your behalf, log in your Twitter ' . 'account and revoke access."}}'; } }); // This is the OAuth callback $app->get('/twitter/oauth_callback', function() use ($app) { if(isset($_GET['oauth_token'])) { $connection = new TwitterOAuth( API_KEY, API_SECRET, $_SESSION['twitter']['request_token'], $_SESSION['twitter']['request_token_secret']); $access_token = $connection->getAccessToken($_REQUEST['oauth_verifier']); if($access_token) { $connection = new TwitterOAuth( API_KEY, API_SECRET, $access_token['oauth_token'], $access_token['oauth_token_secret']); // Set Twitter API version to 1.1. $connection->host = "https://api.twitter.com/1.1/"; $params = array('include_entities' => 'false'); $content = $connection->get('account/verify_credentials', $params); if($content && isset($content->screen_name) && isset($content->name)) { $_SESSION['twitter'] = array( 'id' => $content->id, 'access_token' => $access_token['oauth_token'], 'access_token_secret' => $access_token['oauth_token_secret'] ); // remove the request token from session unset($_SESSION['twitter']['request_token']); unset($_SESSION['twitter']['request_token_secret']); // Twitter's OAuth access tokens are permanent until revoked so // we try to update them when a tweeterer tries to give access // permissions again $sql = "SELECT * FROM twitterers WHERE twitter_id='$content->id'"; $result = DBConnection::getInstance()->getHandler()->query($sql); if($result->num_rows) { $sql = "UPDATE twitterers SET " . "access_token = '" . mysql_real_escape_string($access_token['oauth_token']) . "', " . "access_token_secret = '" . mysql_real_escape_string($access_token['oauth_token_secret']) . "' " . "WHERE twitter_id ='" . $content->id . "'"; } else { $sql = "INSERT INTO twitterers(twitter_id, access_token, access_token_secret) " . "VALUES ('" . mysql_real_escape_string($content->id) . "','" . mysql_real_escape_string($access_token['oauth_token']) . "','" . mysql_real_escape_string($access_token['oauth_token_secret']) . "')"; } DBConnection::getInstance()->getHandler()->query($sql); echo '{"message":{"text":"Everything is ok! Laplacianlab\'s SDSS ' . 'can now tweet trading signals on your behalf. Please, if you no ' . 'longer want the SDSS to tweet on your behalf, log in your Twitter ' . 'account and revoke access."}}'; } else { echo '{"error":{"text":"Login error"}}'; } } } else { echo '{"error":{"text":"Login error"}}'; } }); $app->run();
此处最重要的是将两块数据存储在数据库中,并允许 SDSS 调用 Twitter 提供的访问权限进行用户身份验证。这两块是访问令牌和访问令牌密钥,它们是永久性的,直到用户注销。因此,社交决策支持系统永远不会存储用户证书,并在另一方面,用户打算注销时,可以删除自己的访问权限。
而基于 PHP 的 SDSS 有了正确的访问令牌和访问令牌密钥,就可以执行如下 Twitter 调用:
// Let's assume there's an object named $user to access the tokens... $connection = new TwitterOAuth( API_KEY, API_SECRET, $user->getAccessToken(), $user->getAccessTokenSecret()); $message = "Hello world! I am Laplacianlab's SDSS and I am tweeting on behalf of a tweeterer."; $connection->post('statuses/update', array('status' => $message));
我们已经拥有所需的所有成分。现在, 我们在 4. 编程实现 PHP RESTful Web 服务 中开始编码的 SDSS API 的 POST 信号/添加已经十分容易完成,所以将它留给您作为一个练习,您可以增添必要的 PHP 代码来发布一些样本数据。
本文展示了如何将 MetaTrader 5 终端与 Twitter 连接,以便您能够发布 EA 的交易信号。我们已经开发出结合了自动交易处理能力与个体认知能力的计算机辅助系统。我们希望人们来验证机自动交易信号,否则 EA 将自动在市场中下单。所以,我们已经打开了一扇门,通往一个全新的、令人兴奋的课题,当人们转发或收藏交易信号时,可以获取有关自动交易系统的知识。这是一个基于以人为本的计算(HBC)模式的实际应用。
部署一个完整的社交决策支持系统是费时的,所以这个练习可以看作是一个想法来建立一个技术创新。我们已经开始开发的 SDSS,它由三个主要部分组成:
具体而言,在第一部分,我们已经实现了 RESTful Web 服务体系结构,可以在 MetaTrader 5 与瘦 PHP Web 应用之间通信,我们也通过 OAuth 协议将 PHP 的 Web 应用与 Twitter 链接。在接下来的部分中,我们将采用文章 MQL5-RPC. Remote Procedure Calls from MQL5: Web Service Access and XML-RPC ATC Analyzer for Fun and Profit(MQL5-RPC 来自 MQL5 的远程过程调用:针对乐趣及获利的网络服务访问及 XML-RPC 自动交易锦标赛分析程序) 中的相同方式编写一个 MQL5-RESTful 框架代码。
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程