MT5信号接入Twitter实战
用REST与OAuth搭建社交决策支持系统
什么是社交决策支持系统(SDSS)
传统自动交易系统依赖EA独立决策并直接下单,但计算机缺乏认知能力,在复杂市况下可能失效。社交决策支持系统(SDSS)基于以人为本的计算(HBC)模式,将MT5终端的EA信号作为数据输出,交由人类专家过滤验证后再决定是否执行。本文以将信号发布到Twitter为例,构建一个轻量SDSS:EA信号经Web服务存储并推文,关注者可作为人工过滤器。
SDSS并非完整商业产品,而是一种技术创新思路。它证明MT5不仅能做本地交易,还能作为信息源与外部社交网络打通,为后续分析信号可靠性、建立知识本体提供基础。对于中线或长线系统,这种人工+自动的混合模式比纯剥头皮自动化更有实用价值。
SDSS整体架构与组件分工
系统由三部分组成:运行在VPS或专用服务器上的MetaTrader 5终端,负责24小时运行EA并准备信号;基于Slim微框架的PHP Web应用,接收JSON信号、存MySQL、调用Twitter API;以及Twitter本身作为社交发布渠道。MT5与PHP应用之间采用RESTful通信,数据格式为JSON,第二部分才会用MQL5的WebRequest实现客户端。
在架构设计中,若仅有一台终端发送信号,可省略终端ID;若扩展多终端,需增加mt5_id字段区分来源。无论规模大小,MT5与Web应用间必须加入认证机制(如Basic Auth+SSL或OAuth),否则通信协议暴露会导致任何人都能伪造信号。
- MT5终端:EA生成信号,等待MQL5 REST客户端(下篇)
- PHP应用:提供/signal/add接口,持久化并转发
- Twitter:通过OAuth授权后由PHP代发推文
- MySQL:存储EA、信号、用户授权令牌
为什么选择REST而非SOAP或XML-RPC
REST、SOAP、XML-RPC是三种主流Web服务范式。SOAP和XML-RPC依赖繁重的XML协议规范,开发者需掌握大量伪语言细节;REST仅利用HTTP原生方法,配合JSON数据,实现极简且响应更快。JSON语义密度高,描述同对象字节数少于XML,降低带宽与解析开销,非常适合MT5这类轻量客户端调用。
Twitter官方API即采用REST风格,本文直接借鉴其设计理念。我们只需一个POST方法接收信号,不必构建完整CRUD,降低学习曲线。但需注意,REST的松散规范意味着安全层要自行补齐,不能依赖协议本身保障。
SDSS API规范与信号数据格式
API根地址为http://api.sdss-your-startup.com,通过POST提交JSON实体。核心资源为/signal/add,参数包含ea_id(EA标识)、symbol(品种如EURUSD)、operation(BUY/SELL)、value(价位)。下方为请求体示例,MT5后续篇将构造相同结构发送。
{
"ea_id": 1,
"symbol": "AUDUSD",
"operation": "BUY",
"value": 0.9281
}
该设计假设单终端场景,若多终端并发,应扩展mt5_id。参数经JSON解码后由PHP写入signals表,并返回带自增id的相同对象确认接收。这种极简契约方便任何客户端对接,也易于调试。
数据库设计与MySQL建表脚本
为支持信号存储与EA管理,需建立sdss库。eas表记录EA元数据,signals表以外键关联EA,并保存品种、方向、价位与时间。下方SQL包含授权用户与示例数据,生产请修改密码。此结构可支撑基础SDSS运作,后续可加twitterers表存授权。
# MySQL database creation...
CREATE DATABASE IF NOT EXISTS sdss;
use sdss;
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;
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>');
建表时采用InnoDB引擎以支持外键。signals.value用DECIMAL(9,5)精确存储汇率,避免浮点误差。实际部署中应为laplacianlab用户设强密码,并限制IP访问。
基于Slim的PHP RESTful服务实现
Slim是PHP微框架,能用极少代码暴露API。项目结构含config、model、public入口。config.php定义库名、用户等常量;DBConnection类用单例封装mysqli;.htaccess重写路由至index.php;入口文件注册Slim并声明/post('/signal/add')。下方展示核心常量与单例。
<?php
// Creating constants.
define('BASE_URL', 'laplacianlab.local');
define('APPLICATION_PATH', realpath(dirname(__FILE__)) . '/../');
define('DB_NAME', 'sdss');
define('DB_USER', 'laplacianlab');
define('DB_PASSWORD', 'password');
define('DB_SERVER', 'localhost');
<?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; }
}
入口脚本引入Slim与DB类,设置响应头为JSON,在闭包中解码请求体并拼SQL插入。注意示例用mysql_real_escape_string防注入,现代环境应改用mysqli预处理。返回json_encode($signal)含新id,便于客户端确认。
<?php
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');
$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);
});
$app->run();
本地测试需改hosts添加127.0.0.1 api.laplacianlab.local,并在Apache建虚拟主机指到public目录。用Firefox RESTClient发POST,正常返回HTTP 200及JSON。下图响应头证明服务可用。
Status Code: 200 OK Connection: Keep-Alive Content-Length: 70 Content-Type: application/json Date: Mon, 07 Apr 2014 18:12:34 GMT Server: Apache/2.4.4 (Win64) PHP/5.4.12 X-Powered-By: PHP/5.4.12
{
"ea_id": 1,
"symbol": "AUDUSD",
"operation": "BUY",
"value": 0.9281,
"id": 22
}
Twitter应用创建与OAuth集成
要在Twitter发信号,先于developer网站建应用,填名称、描述、网站、回调URL,权限设为读和写。记下API_KEY、API_SECRET、OAUTH_CALLBACK写入config。OAuth 2.0流程中,用户访问/tweet-signals时跳转Twitter授权,回调存access_token与secret于twitterers表,之后PHP可代发。
define('API_KEY', 'akMnfXR45MkoaWbZoPiu3');
define('API_SECRET', '45Mkoa54NcvQRBbf119qWerty0DnIW45MncvFgqw');
define('OAUTH_CALLBACK', 'http://api.laplacianlab.local/twitter/oauth_callback');
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库简化调用。composer.json需含slim与abraham/twitteroauth。授权后,用$connection->post('statuses/update', array('status'=>$msg))发推。SDSS永不存用户密码,仅持令牌,用户可随时撤权。
// 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));
常见坑与对比总结
实践中易错点:hosts与虚拟主机未配导致本地域名无法解析;Slim旧版路由大小写敏感;mysql_*函数已废弃应迁移mysqli;OAuth回调URL须与Twitter后台完全一致含http。相比直接MT5信号服务,自建SDSS灵活但需维护基建;适合个性化社交分发而非跟单托管。
本文第一部分打通了MT5→Web→Twitter通路,第二部分将用MQL5 WebRequest补全终端侧客户端。读者可延伸加人工验证队列、信号评分等HBC应用。参考原文:https://www.mql5.com/zh/articles/925