Loading ...

发明者量化API文档

Author: 小小梦, Created: 2017-11-27 09:05:08, Updated: 2019-06-20 11:33:22

[TOC]

  • 1. 基础说明

    • 1.1 入门

      FMZ量化平台能够做什么?

      FMZ(发明者)量化平台(原BotVS)是国内最专业的量化社区,在这里你可以学习、编写、分享、买卖量化策略,在线回测和使用模拟盘模拟交易,运行、公开、围观实盘机器人。支持传统的商品期货与易盛外盘期货, 也支持几乎所有的常用的数字货币交易所。FMZ量化平台使用指南

      如果我即没有编程知识,也不懂金融,可以在平台实现量化交易么?

      当然可以,我们平台针对还没入门的新手有一套完整的教程,只需要学习一两天就可以在平台上愉快的玩耍了:零基础入门教程网易云课堂教程

      可用哪些编程语言实现我的策略?

      FMZ支持使用 javascript 、python 、C++ 、麦语言(Mylanguage)编写策略。javascript快速入门python快速入门,几种语言中掌握其中一种就足够了。

      除了支持编写代码方式编写策略,还可以使用可视化模块创建策略。

      麦语言(Mylanguage)版本使用文档

      注意: JavaScript 语言和 C++ 语言的策略,回测是在浏览器端进行,实盘机器人或者模拟盘机器人(即BotVS这个模拟盘)运行不用安装任何其它软件、库或模块。

      python 语言,回测是在托管者上进行,可以在发明者量化的公共服务器上回测,也可以在用户自己的托管者上回测。实盘和回测都依赖托管者所在系统上安装的python,如果需要使用一些库,需要自行安装。(公共服务器上只支持常用的库)

      使用 python 语言编写的策略时,如果托管者所在系统环境同时安装了python2 和 python3 ,可以在策略开始第一行设置策略运行时启动的python版本,

      如下代码范例,第一行编写代码 #!python3 ,启动python3 运行策略代码,如需使用python2启动策略 编写 #!python2

      #!python3
      def main():
          Log("测试")
          Log(exchange.GetAccount())
      

      什么是托管者?

      托管者可以理解为您的交易策略的执行者,负责复杂的数据请求,数据接收,网络链接,日志回传等等工作。托管者运行在您的服务器上,即使FMZ网站出现网络故障,也不影响您的托管者运行。托管者可运行在Linux, Windows, mac os, android, 树莓派等系统上。 托管者页面, Linux安装步骤

      支持的交易所

      类型
      商品期货 Futures_CTP, 支持国内所有期货公司
      外盘易盛 Futures_Esunny
      数字货币现货 AEX BHEX BIT.CC Bibox BigONE
      Binance Bit-Z BitFlyer BitMax -
      Bitfinex Bithumb Bitpie Bitstamp Bittrex
      Bizu CoinBene CoinEx CoinPlus STEX
      Coincheck Coinone Coinw DigiFinex DragonEx
      EXX FCoin GateIO HitBTC Quoine
      Huobi KEX Korbit Kraken KuCoin
      LiveCoin OKCoin_EN OKEX (V1版本) OKEX_V3 (V3版本) BW
      WEX ZB ZBG Zaif Poloniex
      数字货币期货和永续 Futures_BitMEX Futures_Deribit Futures_GateIO Futures_HuobiDM Futures_OKCoin (V1版本)
      Futures_OKEX_V3 (V3版本)
      数字货币现货模拟交易所 WexApp
      数字货币现货杠杆交易所 OKEX_V3 Huobi pro
    • 1.2 回测系统

      什么是回测系统,有什么用?

      当您完成一个策略的量化工作后,怎么才能知道您这个策略的逻辑、策略收益方向等基本情况,赚钱不赚钱?当然我们不能直接拿真金白银人民币去交易市场上跑策略,我们可以用历史数据来测试您的策略,看看您的策略在历史数据中盈利如何,是亏钱还是赚钱。如何使用回测系统

      回测系统的数据准确么,结果可信么?

      FMZ将回测分为实盘级和模拟级,实盘级完全按照完整的历史数据回测,模拟级生成每隔一段时间的k线来进行回测,两者都是根据真实历史数据回测的,但实盘级数据更精准,结果更加可信。模拟级别回测机制说明 但是回测仅仅是策略在历史数据下的表现,历史数据并不能完全代表将来的行情,历史行情可能重演,也可能飞出黑天鹅。所以对待回测结果要理性、客观看待。 回测可以自定义数据源,参考2.3.9 SetData条目。用于回测目前平台无数据的交易对。

      python 策略回测时应注意的问题:

      由于python 回测机制比较特殊,在策略中必须调用行情接口,历史数据才会正常回溯。否则会造成卡死。 主循环上需要加上Sleep函数,设置一个适当的参数,例如:Sleep(500)

      回测系统中的数据

      回测模式分为 模拟级别回测实盘级别回测

      • 模拟级别回测 模拟级别回测时,回测系统中的数据当前的成交价,例如 :

        var ticker = exchange.GetTicker()
        Log(ticker.Last)
        

        其中的 ticker.Last 是根据 K线数据为基础,生成的模拟tick数据。 盘口的买一价,卖一价,根据这个最新成交价生成。 回测系统其余数据均为填充数据,不具有使用价值。

      • 实盘级别回测 实盘级别回测时,回测系统中的数据当前的成交价,是真实的逐笔记录的数据。 盘口的买一价,卖一价,根据这个最新成交价生成。 回测系统其余数据均为填充数据,不具有使用价值。

  • 2. 代码说明

    • 2.1 经典策略框架

      • 策略编写目前可以使用 Javascript 或者 Python 又或 C++ , 更多编程语言计划支持中…
      • main() 为入口函数
      • onexit() 为正常退出扫尾函数,最长执行时间为5分钟,可以不声明,如果超时会报错 interrupt 错误。
      • onerror() 为异常退出函数,最长执行时间为5分钟,可以不声明。
      • init() 为初始化函数,策略程序会在开始运行时自动调用,可不声明。
      # 注意:
      # 1、回测系统不支持 onerror() 
      # 2、在实盘或者BotVS模拟盘中,先触发了 onerror() 函数后,就不会再触发 onexit() 函数。
      # 3、注意在 JavaScript / Python / C++ 语言编写的策略中,需要在策略主循环中调用Sleep函数,
      #    回测用于控制回测时间序列回溯速度。实盘用于控制策略轮询时间间隔,从而控制访问交易所API接口的频率。
      
      • main() 入口函数说明:

        获取机器人ID

        function main(robotId) {                # main 函数可以接收一个 参数(参数名 可以自定义,比如:robotId),接收传来的机器人 ID ,让策略可以获取
                                                # 当前机器人的ID 。
            Log("当前机器人ID:", robotId)        
        }
        

      策略基本框架范例:

      function onTick(){
          //在这里写策略逻辑,将会不断调用
      }
      function main(){
          while(true){
              onTick();
              Sleep(60000);
          }
      }
      

      举个最简单的例子,如果我想每隔1秒种就在交易所挂一个价格为100,数量为1的买单,可以这么写:

      function onTick(){
          exchange.Buy(100,1);
      }
      function main(){
          while(true){
              onTick();
              Sleep(1000);//暂停多久可自定义,单位为毫秒(1秒=1000毫秒)
          }
      }
      

      经典的 商品期货 策略架构:

      function main(){
          while(true){
              if(exchange.IO("status")){
                  exchange.SetContractType("MA000")
                  var ticker = exchange.GetTicker()
                  Log("MA000 ticker:", ticker)
                  LogStatus(_D(), "已经连接CTP !")
              } else {
                  LogStatus(_D(), "未连接CTP !")
              }
              Sleep(1000)
          }
      }
      
    • 2.2 全局常量、数据结构

      • 2.2.1 全局常量

        • exchange

        可视为一个交易所对象,默认为策略参数中添加的第一个交易所,所有与交易所的数据交互,都通过这个对象里面的函数实现。

        • 回测添加交易所对象

          img

        • 实盘机器人页面添加交易所对象

          img

        • exchanges

          exchange的数组,包含多个交易所对象,exchanges[0] 即是 exchange 。

          img

        • 订单状态

        常量名 定义
        ORDER_STATE_PENDING 未完成 0
        ORDER_STATE_CLOSED 已经完成 1
        ORDER_STATE_CANCELED 已经取消 2
        • 订单买卖类型。
        常量名 定义
        ORDER_TYPE_BUY 0
        ORDER_TYPE_SELL 1
        • 仓位类型
        常量名 定义
        PD_LONG 多头仓位(CTP用closebuy_today平仓) 0
        PD_SHORT 空头仓位(CTP用closesell_today平仓) 1
        PD_LONG_YD 昨日多头仓位(用closebuy平) 2
        PD_SHORT_YD 昨日空头仓位(用closesell平) 3
        • 策略参数设置

          在设置策略参数时,可以使用 @ 符号来控制参数显示依赖。 如图:

          img

          第一个参数 名称为 test1 ,参数类型 是下拉框,并且有三个选项,下拉框中每个选项对应的索引是 0, 1, 2 , test1在代码中是 全局变量,值为 选项索引 ,可以直接访问。 第二个参数 名称为 test2 ,参数类型 是数值型,参数名后 @test1==2 的意思是, 该参数 test2 显示或者隐藏是基于 test1的, test1这个变量值等于2的时候(即 下拉框选择 第三个选项,因为第三个选项的索引是2), test1 == 2 为真,则显示 test2。否则隐藏 test2 这个参数。

          如图:

          img

          img

      • 2.2.2 数据结构

        部分函数 会附带 在调用时 请求返回的原始JSON信息,该原始JSON数据储存在 返回对象的 Info 属性中,以下是各个数据结构的主要属性描述。

        • Trade

          获取所有交易历史(非自己),由GetTrades函数返回。

          {
              Time    :时间(Unix timestamp 毫秒)
              Price   :价格
              Amount  :数量
              Type    :订单类型, 参考常量里的订单类型
          }
          
        • Ticker

          市场行情 由GetTicker函数返回

          {
              High    :最高价
              Low     :最低价
              Sell    :卖一价
              Buy     :买一价
              Last    :最后成交价
              Volume  :最近成交量
          }
          
        • Record

          标准OHLC结构, 用来画K线和指标分析用的,由GetRecords函数返回此结构数组

          {
              Time    :一个时间戳, 精确到毫秒,与Javascript的 new Date().getTime() 得到的结果格式一样
              Open    :开盘价
              High    :最高价
              Low     :最低价
              Close   :收盘价
              Volume  :交易量
          }
          
        • Order

          订单结构, 由GetOrder , GetOrders函数返回

          {
              Id          :交易单唯一标识
              Price       :下单价格
              Amount      :下单数量
              DealAmount  :成交数量
              AvgPrice    :成交均价,                     # 注意 ,有些交易所不提供该数据,不提供的设置为 0 。 
              Status      :订单状态, 参考常量里的订单状态
              Type        :订单类型, 参考常量里的订单类型
          }
          

          订单的状态 Order结构里的Status值

          全局常量 意义
          ORDER_STATE_PENDING 未完成
          ORDER_STATE_CLOSED 已关闭
          ORDER_STATE_CANCELED 已取消
          ORDER_STATE_UNKNOWN 未知状态(其它状态)

          ORDER_STATE_UNKNOWN 状态,可以调用exchange.GetRawJSON获取原始订单状态信息,查询交易所文档,查看具体描述。

          订单的类型 Order结构里的Type值

          全局常量 意义
          ORDER_TYPE_BUY 买单
          ORDER_TYPE_SELL 卖单
        • MarketOrder

          市场深度单,即 GetDepth 返回数据中 Bids 、Asks 数组中的元素的数据结构。

          {
              Price   :价格
              Amount  :数量
          }
          
        • Depth

          市场深度,由GetDepth函数返回

          {
              Asks    :卖单数组, MarketOrder数组, 按价格从低向高排序
              Bids    :买单数组, MarketOrder数组, 按价格从高向低排序
          }
          
        • Account

          账户信息, 由GetAccount函数返回

          {
              Balance         :余额(人民币或者美元, 在Poloniex交易所里ETC_BTC这样的品种, Balance就指的是BTC的数量, Stocks指的是ETC数量)
              FrozenBalance   :冻结的余额
              Stocks          :BTC/LTC数量, 数字货币现货为当前可操作币的余额(去掉冻结的币), 数字货币期货的话为合约当前可用保证金(传统期货无此属性)
              FrozenStocks    :冻结的BTC/LTC数量(传统期货无此属性)
          }
          
        • Position

          期货交易中的持有仓位信息, 由GetPosition()函数返回此结构数组

          {
              MarginLevel     :杆杠大小, OKCoin为10或者20。
              Amount          :持仓量, OKCoin表示合约的份数(整数且大于1)
              CanCover        :可平量, 只有股票有此选项, 表示可以平仓的数量(股票为T+1)今日仓不能平
              FrozenAmount    :仓位冻结量
              Price           :持仓均价
              Profit          :持仓浮动盈亏(数据货币单位:BTC/LTC, 传统期货单位:RMB, 股票不支持此字段, 注: OKCoin期货全仓情况下指实现盈余, 并非持仓盈亏, 逐仓下指持仓盈亏)
              Type            :PD_LONG为多头仓位(CTP中用closebuy_today平仓), PD_SHORT为空头仓位(CTP用closesell_today)平仓, (CTP期货中)PD_LONG_YD为咋日多头仓位(用closebuy平), PD_SHORT_YD为咋日空头仓位(用closesell平)
              ContractType    :商品期货为合约代码, 股票为'交易所代码_股票代码', 具体参数SetContractType的传入类型
          }
          
    • 2.3 市场信息

      以下函数均可通过exchange或exchanges[x]对象调用,例如:exchange.GetTicker(); 或 exchanges[0].GetTicker();返回市场行情

      带有网络访问的API函数调用的重要提示:

      # 在调用任何 访问交易所接口的 API 函数时(如 GetTicker、Buy、CancelOrder 等) 都有可能由于各种原因导致访问失败。
      # 所以要对这些 函数的 调用做容错处理,举例: GetTicker 获取行情数据函数可能由于,交易所服务器问题,网络传输问题等
      # 导致GetTicker 函数返回值 为 null ,这时就要对 GetTicker 的调用做容错处理。
      # JS 描述
      
      var ticker = exchange.GetTicker()
      if(ticker == null){
          // 重试 ,或者其它处理逻辑。
      }
      
      # 另外,对于策略的容错性能测试,FMZ专门在回测中增加了独有的容错模式回测。
      # 回测系统可以根据设置的参数随机给一些实盘时会发生网络访问的API调用返回一些失败调用时的返回值。
      # 可以快速初步检测程序在实盘中的健壮性。
      

      如图: img

      • 2.3.1 GetTicker

        exchange.GetTicker();

        获取市场当前行情

        返回值: Ticker结构体

        Ticker结构体包含以下变量:

        数据类型 变量名 说明
        object Info 交易所返回的原始结构
        number High 最高价
        number Low 最低价
        number Sell 卖一价
        number Buy 买一价
        number Last 最后成交价
        number Volume 最近成交量
        function main(){
            var ticker = exchange.GetTicker();
            Log("High:", ticker.High, "Low:", ticker.Low, "Sell:", ticker.Sell, "Buy:", ticker.Buy, "Last:",
                ticker.Last, "Volume:", ticker.Volume);
        }
        
      • 2.3.2 GetDepth

        exchange.GetDepth()

        获取交易所订单薄

        返回值:Depth结构体

        Depth结构体包含两个结构体数组,分别是Asks[]和Bids[],Asks和Bids包含以下结构体变量:

        数据类型 变量名 说明
        number Price 价格
        number Amount 数量

        例如我想获取当前卖二价,可以这么写代码:

        function main(){
            var depth = exchange.GetDepth();
            var price = depth.Asks[1].Price;
            Log("卖二价为:", price);
        }
        
      • 2.3.3 GetTrades

        (部分交易所不支持,具体返回的数据是多少范围内的成交记录,因交易所而定,需要根据具体情况处理)

        exchange.GetTrades()

        获取交易所交易历史(非自己)

        返回值: Trade 结构体 数组

        Trade 结构体

        数据类型 变量名 说明
        string 或 number (根据交易所返回类型而定) Id 交易所返回的此Trade的唯一Id
        number Time 时间Unix timestamp 毫秒
        number Price 价格
        number Amount 数量
        const Type 订单类型:ORDER_TYPE_BUY, ORDER_TYPE_SELL。分别为买单,值为0,卖单,值为1
        //在模拟回测中数据为空,必须实盘才有交易历史
        function main(){
            var trades = exchange.GetTrades();
            Log("id:", trades[0].Id, "time:", trades[0].Time, "Price:", trades[0].Price, "Amount:", trades[0].Amount,
                "type:", trades[0].Type);
        }
        
      • 2.3.4 GetRecords

        (部分交易所没有提供K线接口,托管者实时收集数据生成K线)

        exchange.GetRecords(Period)

        返回一个K线历史, K线周期在创建机器人时指定 ,如果 在调用 exchange.GetRecords() 函数时 指定了参数, 获取的就是按照该参数周期的K线数据,如果没有参数, 按照机器人参数上设置的K线周期或者回测页面设置的K线周期返回K线数据。 参数值:PERIOD_M1 指1分钟, PERIOD_M5 指5分钟, PERIOD_M15 指15分钟, PERIOD_M30 指30分钟, PERIOD_H1 指1小时, PERIOD_D1 指一天。

        返回值: Record结构体数组 K线数据, 会随时间累积,最多累积到2000根,然后会更新加入一根,同时删除一根最早时间的K线柱(如队列进出)。

        Record结构体包含以下变量:

        数据类型 变量名 说明
        number Time 一个时间戳, 精确到毫秒,与Javascript的 new Date().getTime() 得到的结果格式一样
        number Open 开盘价
        number High 最高价
        number Low 最低价
        number Close 收盘价
        number Volume 交易量
        function main(){
            var records = exchange.GetRecords(PERIOD_H1);
            Log("第一根k线数据为,Time:", records[0].Time, "Open:", records[0].Open, "High:", records[0].High,
                "Low:", records[0].Close, "Volume:", records[0].Volume);
            Log("第二根k线数据为,Time:", records[1].Time, "Open:", records[1].Open, "High:", records[1].High,
                "Low:", records[1].Close, "Volume:", records[1].Volume);
        }
        

        注意:

        GetRecords 接口 获取K线数据 有2种情况:

        • 1 交易所提供了K线数据接口,这种情况,获取的数据是交易所直接返回的数据。

        • 2 交易所没有提供K线数据接口,FMZ 底层在 每次用户调用GetRecords 时 获取 交易所最近成交记录(即 GetTrades() 函数,合成K线数据。)

        详细 参见帖子: 交易所 API 特殊问题汇总

        C++ 语言 如果要自己构造 K线 数据有以下代码范例:

        #include <sstream>
        void main() { 
            Records r;
            r.Valid = true;
            for (auto i = 0; i < 10; i++) {
                Record ele;
                ele.Time = i * 100000;
                ele.High = i * 10000;
                ele.Low = i * 1000;
                ele.Close = i * 100;
                ele.Open = i * 10;
                ele.Volume = i * 1;
                r.push_back(ele);
            }
            Log(r);                      // 输出显示  :     Records[10]
            auto ma = TA.MA(r,10);       
            Log(ma);                     // 输出显示  :   [nan,nan,nan,nan,nan,nan,nan,nan,nan,450]
        }
        
      • 2.3.5 GetRawJSON

        exchange.GetRawJSON()

        返回最后一次REST API请求返回的原始内容(字符串), 可以用来自己解析扩展信息

        返回值 : string类型

        模拟测试的话,会一直返回一个空字符串, 只在真实环境下有效

        function main(){
            exchange.GetAccount(); 
            var obj = JSON.parse(exchange.GetRawJSON());
            Log(obj);
        }
        
      • 2.3.6 GetRate

        exchange.GetRate()

        返回交易所使用的流通货币与当前显示的计价货币的汇率, 返回1表示禁用汇率转换

        返回值:number类型

        # 注意: 如果没有调用 exchange.SetRate() 设置过 转换汇率 , GetRate 默认返回的汇率值是 1 ,
        # 即 当前显示的 计价货币 没有发生 过 汇率转换。
        # 如果使用 exchange.SetRate() 设置过一个汇率值,例如 7, 那么 当前 exchange 这个交易所对象代表的交易所的流通货币
        # 计价的 行情 、深度、下单价格 等等所有 价格信息,都会被 乘以 设置的汇率 7 ,进行转换。
        # 例如 exchange 是 以美元为计价货币的交易所,  exchange.SetRate(7) 后, 机器人所有价格都会被 乘 7 转换成 接近
        # CNY 的价格。 此时 使用 GetRate 获取的 汇率值  就是 7。
        
      • 2.3.7 GetUSDCNY

        exchange.GetUSDCNY()

        返回美元最新汇率(yahoo提供的数据源) 或 OKEX期货合约 使用的美元汇率

        返回值:number类型

        # 注意:
        # 当 交易所对象 exchange 为 非OKEX期货交易所对象时:
        # 返回的是 yahoo提供的 美元汇率
        
        # 当 交易所对象 exchange 为 OKEX期货交易所对象时:
        # 返回的是 OKEX 交易所 设定的 美元汇率, 可能和 yahoo 提供的数据, 或者 一些 外汇数据 上的美元汇率不一致。
        
      • 2.3.8 切换行情模式

        exchange.IO("websocket")

        切换行情通信协议到websocket(默认为rest),切换之后获取行情的方式会改变,GetTicker()和GetDepth()将会切换为websocket协议来更新,由原来的主动获取行情数据变为被动获取行情数据 目前只支持火币和OK交易所

        exchange.IO("mode", 0) 立即返回模式, 如果当前还没有接收到交易所最新的行情数据推送, 就立即返回旧的行情数据,如果有新的数据就返回新的数据

        exchange.IO("mode", 1) 缓存模式(默认模式),如果当前还没有收到交易所最新的行情数据(同上一次接口获取的数据比较), 就等待接收然后再返回, 如果调用该函数之前收到了最新的行情数据,就立即返回最新的数据

        exchange.IO("mode", 2) 强制更新模式, 进入等待一直到接收到交易所下一次的最新推送数据后返回

        如果想第一时间获取最新的行情可以切换到websocket后不Sleep的立即检测数据, GetTicker, GetDepth用缓存模式进行工作,如:

        exchange.IO("websocket");
        while (true) {
          Log(exchange.GetTicker());
        }
        
      • 2.3.9 SetData(自定义行情数据)

        exchange.SetData(arr) , 切换回测数据源,使用自定义的K线数据 参数 arr ,是一个元素为K线柱数据的数组(即:K线数据数组) 暂时仅支持 JavaScript 回测。

        arr数组中,单个元素的数据格式:

        [
            1530460800,    // time     时间戳
            2841.5795,     // open     开盘价
            2845.6801,     // high     最高价
            2756.815,      // low      最低价
            2775.557,      // close    收盘价
            137035034      // volume   成交量
        ]
        

        数据源可以放在 “模板类库” 中 比如:创建一个模板名字叫 “测试导入数据” 模板,然后在模板中写数据导入代码。

        function init() {                                                          // 模板中的 init 初始化函数会在加载模板时,首先执行,确保 exchange.SetData(arr) 函数先执行,初始化,设置数据给回测系统。
            var arr = [                                                            // 回测的时候需要使用的K线数据
                [1530460800,2841.5795,2845.6801,2756.815,2775.557,137035034],      // 时间最早的一根 K线柱 数据
                ... ,                                                              // K线数据太长,用 ... 表示,数据此处省略。
                [1542556800,2681.8988,2703.5116,2674.1781,2703.5116,231662827]     // 时间最近的一根 K线柱 数据
            ]
            exchange.SetData(arr)                                                  // 导入上述 自定义的数据
            Log("导入数据成功")
        }
        
        # 注意:
        # 一定要在初始化时,首先导入自定义数据(即调用 exchange.SetData 函数设置数据)
        # 数据源模板编写,数据粘贴好以后,保存模板,需要使用这个自定义数据,只需 在您的 策略编辑页面 , 让需要使用这个数据
        # 的策略引用上这个数据源模板就可以了(即:勾选上这个模板)
        # 暂时仅支持 JavaScript 回测。
        # 
        # 自定义的K线数据周期必须和回测页面设置的底层K线周期一致,即:自定义的K线数据,一根K线时间是1分钟,那么回测中
        # 设置的底层K线周期也要设置为1分钟。
        

        img

        也可以把数据写在策略里面,同样数据初始化写在策略的 init 函数中,在策略初始的时候首先执行自定义数据的导入操作。 方便一点的还是用模板,只用勾选上就可以使用自定义数据,不勾选就是不使用自定义数据。

    • 2.4 交易操作

      以下函数均可通过exchange或exchanges[x]对象调用,例如:exchange.Sell(100, 1); 在交易所下一个价格为100,数量为1的买单

      • 2.4.1 Buy

        exchange.Buy(Price, Amount)

        下买单, 返回一个订单ID

        参数值: price为订单价格,number类型,Amount为订单数量,number类型

        返回值:string类型 或 数值类型 (具体类型根据各个交易所返回类型而定。)

        返回订单编号,可用于查询订单信息和取消订单

        function main(){
            var id = exchange.Buy(100, 1);
            Log("id:", id);
        }
        
        • 市价单

          注意:需要交易所的下单接口,支持市价单。 (下单类型为 买单 时,下单量参数为 计价币为单位的金额) 数字货币期货市价单方式下单,下单量参数单位为:合约张数。

          // 例如交易对:ETH_BTC
          // 市价单买入
          exchange.Buy(-1, 0.1)    // 下市价单 买入,买入 0.1 个 BTC(计价币)金额的 ETH 币。 
          
      • 2.4.2 Sell

        exchange.Sell(Price, Amount)

        下卖单,返回一个订单ID

        参数值:price为订单价格,number类型,Amount为订单数量,number类型

        返回值:string类型 或 数值类型 (具体类型根据各个交易所返回类型而定。)

        返回订单编号,可用于查询订单信息和取消订单

        function main(){
            var id = exchange.Sell(100, 1);
            Log("id:", id);
        }
        
        • 市价单

          注意:需要交易所的下单接口,支持市价单。 (下单类型为 卖单 时,下单量参数 为 卖出的 操作币 个数) 数字货币期货市价单方式下单,下单量参数单位为:合约张数。

          // 例如交易对:ETH_BTC
          // 市价单卖出
          exchange.Sell(-1, 0.2)   // 注意: 下市价单 卖出,卖出 0.2 个 ETH 。
          
      • 2.4.3 CancelOrder

        exchange.CancelOrder(orderId)

        取消某个订单

        参数值:orderid为订单编号,string类型 或 数值类型。 (具体类型根据各个交易所下单时返回类型而定)

        返回值:bool类型

        返回操作结果,true表示取消订单请求发送成功,false取消订单请求发送失败(只是发送请求成功,交易所是否取消订单最好调用exchange.GetOrders()查看)

        function main(){
            var id = exchange.Sell(99999, 1);
            exchange.CancelOrder(id);
        }
        
        # FMZ 的 API 函数 , 可以 产生日志输出的函数 比如 Log, Buy, 
        # CancelOrder 等 都可以 在必要 参数 后跟 一些 附带输出 参数,
        # 比如: exchange.CancelOrder(orders[j].Id, orders[j]) 这样就是 
        # 在取消orders[j] 这个订单时 , 附带输出这个订单信息。
        
      • 2.4.4 GetOrder

        (部分交易所不支持)

        exchange.GetOrder(orderId)

        根据订单号获取订单详情

        参数值: orderid为要获取的订单号,string类型 或 数值类型。(具体类型根据各个交易所返回类型而定)

        返回值: Order结构体

        数据类型 变量名 说明
        object Info 交易所返回的原始结构
        string Id 交易单唯一标识
        number Price 下单价格
        number Amount 下单数量
        number DealAmount 成交数量
        number AvgPrice 成交均价(有些交易所 不支持该 字段,不支持则设置0)
        const Status 订单状态, ORDER_STATE_PENDING : 未完成 、 ORDER_STATE_CLOSED :已完成 、 ORDER_STATE_CANCELED : 已取消 、 ORDER_STATE_UNKNOWN : 未知状态
        const Type 订单类型, ORDER_TYPE_BUY :买单,ORDER_TYPE_SELL : 卖单
        function main(){
            var id = exchange.Sell(99999, 1);
            var order = exchange.GetOrder(id);//参数id为订单号码,需填入你想要查询的订单的号码
            Log("Id", order.Id, "Price:", order.Price, "Amount:", order.Amount, "DealAmount:",
                order.DealAmount, "Status:", order.Status, "Type:", order.Type);
        }
        
      • 2.4.5 GetOrders

        exchange.GetOrders()

        获取所有未完成的订单

        返回值: Order结构体数组

        order结构体可参考GetOrder()函数说明

        function main(){
            exchange.Sell(99999, 1);
            exchange.Sell(88888, 1);
            var orders = exchange.GetOrders();
            Log("未完成订单一的信息,ID:", orders[0].Id, "Price:", orders[0].Price, "Amount:", orders[0].Amount,
                "DealAmount:", orders[0].DealAmount, "type:", orders[0].Type);
            Log("未完成订单二的信息,ID:", orders[1].Id, "Price:", orders[1].Price, "Amount:", orders[1].Amount,
                "DealAmount:", orders[1].DealAmount, "type:", orders[1].Type);
        }
        

        GetOrders() 函数 获取的是当前设置的 交易对 或者 OKEX合约 的未完成挂单信息。

        // 测试 OKex 合约 交易, GetOrders 获取的是否是 所有 未完成合约订单。
        function main(){
            // 下一个 当周的  买单 ,价格减去 50 保证 不会成交,挂单。
            exchange.SetContractType("this_week")
            exchange.SetDirection("buy")
            var ticker = exchange.GetTicker()
            Log(ticker)
            exchange.Buy(ticker.Last - 50, 1)
            // 下一个 季度的  卖单, 价格加上 50 保证 不会成交,挂单,并已经切换成了 季度合约。
            exchange.SetContractType("quarter")
            exchange.SetDirection("sell")
            ticker = exchange.GetTicker()
            Log(ticker)
            exchange.Sell(ticker.Last + 50, 1)
            // 获取 未完成的订单
            Log("orders", exchange.GetOrders())
        }
        

        img 获取的未完成的订单信息:[{“Id”:17116430886,“Amount”:1,“Price”:808.4,“DealAmount”:0,“AvgPrice”:0,“Status”:0,“Type”:1,“ContractType”:“quarter”}] 由此可见,GetOrders 获取的订单 仅仅是当前 设置合约的未完成的订单。

      • 2.4.6 SetPrecision

        exchange.SetPrecision(PricePrecision, AmountPrecision)

        设置价格与品种下单量的小数位精度, 设置后会自动截断

        参数值:PricePrecision为number类型,用来控制价格后面的小数点位,AmountPrecision为number类型,用来控制数量后面的小数点位

        PricePrecision和AmountPrecision都必须是整型number

        function main(){
            exchange.SetPrecision(2, 3); //设置价格小数位精度为2位, 品种下单量小数位精度为3位
        }    
        
        # 注意:回测不支持该函数。
        
      • 2.4.7 SetRate

        exchange.SetRate(scale)

        设置交易所的流通货币的汇率

        参数值:scale为number类型

        返回值:为number类型

        function main(){
            exchange.SetRate();  // 如果不加参数,则恢复系统内置汇率 
            exchange.SetRate(1); // 就是禁用汇率转换
        }
        
        # 注意: 如果没有调用 exchange.SetRate() 设置过 转换汇率 , GetRate 默认返回的汇率值是 1 ,
        # 即 当前显示的 计价货币 没有发生 过 汇率转换。
        # 如果使用 exchange.SetRate() 设置过一个汇率值,例如 7, 那么 当前 exchange 这个交易所对象代表的交易所的流通货币
        # 计价的 行情 、深度、下单价格 等等所有 价格信息,都会被 乘以 设置的汇率 7 ,进行转换。
        # 例如 exchange 是 以美元为计价货币的交易所,  exchange.SetRate(7) 后, 机器人所有价格都会被 乘 7 转换成 接近
        # CNY 的价格。 此时 使用 GetRate 获取的 汇率值  就是 7。
        
      • 2.4.8 IO

        exchange.IO("api", httpMethod, resource, params)

        调用交易所其它功能接口

        参数值:httpMehod为string类型,填入请求类型"POST"或者"GET",resource为string类型,填入路径,params为string类型,填入交互参数

        使用此函数需要去交易所了解该交易所的API接口,用来扩展FMZ没有添加的功能(提交POST请求不必担心参数加密过程,FMZ在底层已经完成加密,只要填入相应参数即可)。 举个例子,比如FMZ平台目前不支持bitfinex交易所的保证金杠杆交易,我们可以通过IO函数来实现这一个功能,按照以下步骤。

        • 先找到bitfinex的API接口说明页面:bitfinex
        • 然后我们得知下单是以POST请求交互的,所以我们把参数httpMethod传入"POST"保证金交易的下单地址为:'https://api.bitfinex.com/v1/order/new’。因为FMZ已经在内部指定了根地址,所以我们只需要把参数resource的值传入"/v1/order/new"就行了。
        • 然后还剩params参数没有填入,params变量代表了所要交互的信息,我们把各种信息以"&"符号链接起来发送即可,我们先到bitfinex查看得知下一个买单或卖单需要5个参数,分别是:symbol,amount,price,side,type。我们分别给这5个参数赋值,假如我们要买莱特币LTC,数量为1个,价格为10,为保证金交易模式,那么我们可以构造这么一个字符串:“symbol=ltc&amount=1&price=10&side=buy&type=limit”。
        • 最后我们把以上结合通过一行代码即可交易:
        function main(){
            exchange.IO("api","POST","/v1/order/new","symbol=ltc&amount=1&price=10&side=buy&type=limit");
        }
        

        全部代码例子可到FMZ策略广场:bitfinex保证金交易查看。

        • 注意: 如果 params 即 Http请求 参数 ,需要传入 JSON 形式的字符串,需要用 单引号 (符号 ’ ) 写在参数值 左右。 例如: bitfinex 交易所
          var message = "symbol=" + basecurrency + quotecurrency + "&amount='" + amount.toString() + "'&price=" + price.toString() + "&side=buy" + "&type=limit"
          var id = exchange.IO("api", "POST", "/v1/order/new", message)
          
        • OKEX 范例:

          function main(){
              //            URL: /api/v1/future_position.do
              /*
              symbol        String 是  btc_usd   ltc_usd    eth_usd    etc_usd    bch_usd
              contract_type String 是  合约类型: this_week:当周   next_week:下周   quarter:季度
              api_key       String 是  用户申请的apiKey
              sign          String 是  请求参数的签名    
              */
              var ret = exchange.IO("api", "POST", "/api/v1/future_position.do", "symbol=eth_usd&contract_type=this_week")
          
              Log(ret)
          }
          

          返回数据:

          {
              "result": true,
              "holding": [{
                  "buy_available": 0,
                  "contract_id": 201876560020041,
                  "sell_amount": 0,
                  "sell_profit_real": 0.07166192,
                  "buy_profit_real": -0.00003518,
                  "contract_type": "this_week",
                  "create_date": 1516881053000,
                  "buy_price_avg": 1093.737,
                  "lever_rate": 10,
                  "sell_price_cost": 933.14087684,
                  "buy_price_cost": 1093.737,
                  "sell_price_avg": 933.14087684,
                  "sell_available": 0,
                  "symbol": "eth_usd",
                  "buy_amount": 0
              }],
              "force_liqu_price": "0.000"
          }
          

        IO 函数修改机器人的其它设置

        • 切换当前交易所的交易对

          exchange.IO("currency", “ETH_BTC”)

          这样就会通过代码切换 机器人 创建时配置的 交易对。

          # 注意:
          1、如果 在OKEX 或者 火币 PRO  切换了 websocket 协议 模式,则不能 使用exchange.IO("currency", "XXX_YYY")
          切换币种。
          2、exchange.IO("currency", "ETH_BTC")   # 仅支持 实盘,回测不支持。
          

        IO 函数切换交易所 API 基地址(REST 协议, 部分交易所 不支持)

        例如:火币交易所 的 API 基地址 , 资料来源: 火币 API 文档 Pro站:国内服务器建议使用 api.huobipro.com ,其它服务器建议使用 api.huobi.pro

        # 切换 基地址 为:api.huobi.pro
        exchanges[0].IO("base", "http://api.huobi.pro")        # exchanges[0] 就是机器人创建时,第一个添加的 交易所对象。
        # 切换 基地址 为:api.huobipro.com
        exchanges[0].IO("base", "http://api.huobipro.com")
        

        切换为杠杠账户模式

        使用 exchange.IO("trade_margin") 切换为杠杠账户模式,下单、获取账户资产 将访问交易所杠杆接口。 使用 exchange.IO("trade_normal") 切换回普通账户模式。

        支持的交易所:

        交易所 备注
        OKEX V3 杠杆账户模式的交易对和普通的有所不同,有些交易对可能没有。
        火币 杠杆账户模式的交易对和普通的有所不同,有些交易对可能没有。
      • 2.4.9 exchange.Log

        exchange.Log(logType, orderId, price, amount)

        不下单, 只记录交易信息 注意:此函数是 exchange 交易所对象的 成员函数,区别于全局 函数 Log() 。 参数值:logType可为LOG_TYPE_BUY,LOG_TYPE_SELL,LOG_TYPE_CANCEL, orderId为订单id,可自定义一个递增数值传入,price为价格,amount为数量

        使用 exchange.Log 可以进行 实盘跟单测试,模拟下单。 可以辅助 记录 下单。

        exchange.Log(LOG_TYPE_BUY, 123, 999, 0.1)      # 下单类型 买入, 订单号:123 , 价格 999 , 数量 0.1
        
      • 2.4.10 exchange.HMAC

        exchange.HMAC(Algo, OutputAlgo, Data, Key) , 支持 md5/sha256/sha512/sha1 的HMAC加密计算, 只支持实盘 exchange.HMAC(“sha256”, “hex”, “xxxxx”, “{{secretkey}}”) 引用 accessKey, 使用 “{{accesskey}}” 引用 secretKey, 使用 “{{secretkey}}” , 也可以使用 明文 “XX…API KEY”。 “{{accessKey}}”、"{{secretkey}}" 方式仅在该函数使用时有效。 OutputAlgo 支持 : “hex” , “base64”

        具体例子:https://www.fmz.com/strategy/128624 Bitmex仓位变化推送微信(wss协议,需要bitmex api ID)

        function main() {
            var APIKEY = "your Access Key(Bitmex API ID)"
            var expires = parseInt(Date.now() / 1000) + 10
            var signature = exchange.HMAC("sha256", "hex", "GET/realtime" + expires, "{{secretkey}}")
            var client = Dial("wss://www.bitmex.com/realtime", 60)
            var auth = JSON.stringify({args: [APIKEY, expires, signature], op: "authKeyExpires"})
            var pos = 0
            client.write(auth)
            client.write('{"op": "subscribe", "args": "position"}')
            while (true) {
                bitmexData = client.read()
                if(bitmexData.table == 'position' && pos != parseInt(bitmexData.data[0].currentQty)){
                    Log('position change', pos, parseInt(bitmexData.data[0].currentQty), '@')
                    pos = parseInt(bitmexData.data[0].currentQty)
                }
            }
        }
        
      • 2.4.11 Go

        exchange.Go(Method, Args…)

        多线程异步支持函数, 可以把所有支持的函数的操作变成异步并发的.(只支持数字货币交易平台)

        参数值:Method为string类型,函数名

        # 注意:该函数 只在实盘运行时 创建多线程执行任务,回测不支持多线程并发执行任务(回测可用,但是还是顺序执行)。
        # 注意:Go 函数 返回对象后,通过该对象 调用其 wait 函数 获取 线程返回数据时,必须 wait 获取完成后,该线程才会自动释放。
        # 简单表述就是,申请的线程 无论执行成功或者失败,必须 由 wait 函数获取到结果,并由托管者自动释放 通过Go 函数申请的线程资源。
        # 如果 最终 wait 函数的返回结果没有被获取,线程资源不会自动释放,会导致申请的线程累积,超过2000个会报错:
        # "too many routine wait, max is 2000" 。
        

        支持的函数: GetTicker, GetDepth, GetTrades, GetRecords, GetAccount, GetOrders, GetOrder, CancelOrder, Buy, Sell, GetPosition

        function main(){
            var a = exchange.Go("GetTicker"); //GetTicker 异步多线程执行 
            var b = exchange.Go("GetDepth"); 
            var c = exchange.Go("Buy", 1000, 0.1); 
            var d = exchange.Go("GetRecords", PERIOD_H1);
            //上面四种操作是并发多线程异步执行, 不会耗时, 立即返回的
            var ticker = a.wait(); //调用wait方法等待返回异步获取ticker结果 
            var depth = b.wait(); //返回深度, 如果获取失败也是有可能返回null的 
            var orderId = c.wait(1000); //返回订单号, 限定1秒超时, 超时返回undefined, 此对像可以继续调用wait等待如果上次wait超时 
        }
        

        注意: 判断undefiend要用typeof(xx) === “undefined”, 因为null==undefined在JavaScript里是成立的

        var records = d.wait(); //等待K线结果 
        var ret = d.wait();  //这里wait了一个已经wait过且结束的异步操作, 会返回null, 并记录出错信息. 
        

        Python与Javascript的区别, Python的wait返回两个参数, 第一个是异步的api返回的结果, 第二个表示是异步调用是否完成

        ret, ok = d.wait(); //ok是一定返回True的, 除非策略被停止 
        ret, ok = d.wait(100); //ok返回False, 如果等待超时, 或者wait了一个已经结束的实例
        
    • 2.5 账户信息

      • 2.5.1 GetAccount

        exchange.GetAccount()

        将返回交易所账户信息

        返回值: Account结构结构体

        Account结构体包含以下变量:

        数据类型 变量名 说明
        object Info 交易所返回的原始结构
        number Balance 可用余额(定价货币余额, ETH_BTC的话BTC为定价货币)
        number FrozenBalance 冻结的余额
        number Stocks 交易货币的可用数量, 数字货币现货为当前可操作币的余额(去掉冻结的币), 数字货币期货的话为合约当前可用保证金(传统期货无此属性) 。
        number FrozenStocks 冻结的交易货币的可用数量(传统期货无此属性)
        function main(){
            var account = exchange.GetAccount();
            Log("账户信息,Balance:", account.Balance, "FrozenBalance:", account.FrozenBalance, "Stocks:",
                account.Stocks, "FrozenStocks:", account.FrozenStocks);
        }
        
      • 2.5.2 GetName

        exchange.GetName()

        返回交易所名称

        返回值: string类型

      • 2.5.3 GetLabel

        exchange.GetLabel()

        返回交易所自定义的标签

        返回值:string类型

      • 2.5.4 GetCurrency

        exchange.GetCurrency()

        返回交易所操作的货币对名称如LTC_BTC, 传统期货CTP返回的固定为STOCK.

        返回值:string类型

      • 2.5.5 GetQuoteCurrency

        exchange.GetQuoteCurrency()

        返回交易所操作的基础货币名称, 例如BTC_CNY就返回CNY, ETH_BTC就返回BTC

        返回值:string类型

    • 2.6 期货交易

      期货支持传统商品期货CTP协议, BTC期货:OKCoin,BitMEX

      • 2.6.1 GetPosition

        exchange.GetPosition()

        获取当前持仓信息, OKCoin可以传入一个参数, 指定要获取的合约类型

        返回值:position结构体数组

        position结构体包含以下变量:

        数据类型 变量名 说明
        object Info 交易所返回的原始结构
        number MarginLevel 杆杠大小, OKCoin为10或者20,OK期货的全仓模式返回为固定的10, 因为原生API不支持
        number Amount 持仓量,OKCoin表示合约的份数(整数且大于1)
        number CanCover 可平量, 只有股票有此选项, 表示可以平仓的数量(股票为T+1)今日仓不能平
        number FrozenAmount 仓位冻结量
        number Price 持仓均价
        number Profit 商品期货:持仓盯市盈亏,数字货币:(数字货币单位:BTC/LTC, 传统期货单位:RMB, 股票不支持此字段, 注: OKCoin期货全仓情况下指实现盈余, 并非持仓盈亏, 逐仓下指持仓盈亏)
        const Type PD_LONG为多头仓位(CTP中用closebuy_today平仓), PD_SHORT为空头仓位(CTP用closesell_today)平仓, (CTP期货中)PD_LONG_YD为昨日多头仓位(用closebuy平), PD_SHORT_YD为昨日空头仓位(用closesell平)
        string ContractType 商品期货为合约代码, 股票为’交易所代码_股票代码’, 具体参数SetContractType的传入类型
        # 注意: GetPosition 函数获取的是所有持仓品种的持仓信息,如果没有持仓返回空数组,所以引用前要先判断。
        function main(){
            exchange.SetContractType("this_week");
            exchange.SetMarginLevel(10);
            exchange.SetDirection("buy");
            exchange.Buy(10000, 2);
            position = exchange.GetPosition();
            if(position.length>0){
                Log("Amount:", position[0].Amount, "FrozenAmount:", position[0].FrozenAmount, "Price:",
                    position[0].Price, "Profit:", position[0].Profit, "Type:", position[0].Type,
                    "ContractType:", position[0].ContractType);
            }
        }
        
      • 2.6.2 SetMarginLevel

        exchange.SetMarginLevel(MarginLevel)

        设置杆杠大小

        参数值:number整型

        设置Buy(多单)或者Sell(空单)的杆杠大小, MarginLevel有5, 10, 20 三个可选参数,OKCoin支持10倍和20倍,如:

        exchange.SetMarginLevel(10)
        
      • 2.6.3 SetDirection

        exchange.SetDirection(Direction)

        设置Buy或者Sell下单类型

        参数值:string类型

        SetDirection 函数设置期货交易方向和下单函数之间的对应关系。

        下单函数 SetDirection 函数的参数设置的方向 备注
        exchange.Buy “buy” 买入开多仓
        exchange.Buy “closesell” 买入平空仓
        exchange.Sell “sell” 卖出开空仓
        exchange.Sell “closebuy” 卖出平多仓

        Direction可以取buy, closebuy, sell, closesell四个参数, 传统期货多出closebuy_today,与closesell_today, 指平今仓, 默认为closebuy/closesell为平昨仓。对于CTP传统期货, 可以设置第二个参数”1”或者”2”或者”3”, 分别指”投机”, “套利”, “套保”, 不设置默认为投机,股票只支持buy与closebuy, 因为股票只能买跟平仓

        function main(){
            exchange.SetContractType("this_week")    // 举例设置 为OKEX期货 当周合约
            exchange.SetMarginLevel(5); //设置杠杆为5倍 
            exchange.SetDirection("buy"); //设置下单类型为做多 
            exchange.Buy(1000, 2); //以1000的价格,合约数量为2下单 
            exchange.SetMarginLevel(5); 
            exchange.SetDirection("closebuy"); 
            exchange.Sell(1000, 2);
        }
        
      • 2.6.4 SetContractType

        SetContractType(ContractType)

        设置合约类型

        参数值:string类型

        传统的CTP期货的ContractType就是指的合约ID, 如SetContractType(“au1506”) 返回合约的详细信息, 如最少一次买多少, 手续费, 交割时间等,主力连续合约为代码为888如MA888, 连续指数合约为000如MA000, 888与000为虚拟合约交易只支持回测, 实盘只支持获取行情。

        订阅虚拟合约成功以后, 返回的字段里面的InstrumentID是主力合约(会在订阅同时获取), 方便策略实盘下单做映射用。

        数字货币合约: 例如: OKCoin期货有this_week, next_week, quarter三个参数

        exchange.SetContractType("this_week"); //设置为当周合约
        

        详细介绍支持的数字货币合约交易所每个交易所的合约命名:

        • OKEX

          exchange.SetContractType("swap")        // 设置为永续合约
          exchange.SetContractType("this_week")   // 设置为当周合约
          exchange.SetContractType("next_week")   // 设置为次周合约
          exchange.SetContractType("quarter")     // 设置为季度合约
          
        • HuobiDM

          exchange.SetContractType("this_week")   // 设置为当周合约 
          exchange.SetContractType("next_week")   // 设置为次周合约
          exchange.SetContractType("quarter")     // 设置为季度合约
          
        • BitMEX

          exchange.SetContractType("XBTUSD")    // 设置为永续合约
          exchange.SetContractType("XBTM19")    // 具体某个时间结算的合约,详情登录BitMEX 查询各个合约代码
          
        • GateIO

          exchange.SetContractType("swap")      // 设置为永续合约,GateIO 目前只有永续合约,不设置默认为swap 永续合约。 
          
        • Deribit

          exchange.SetContractType("BTC-PERPETUAL")    // 设置为永续合约
          exchange.SetContractType("BTC-27APR18")      // 具体某个时间结算的合约,详情参看 Deribit 官网。
          
      • 2.6.5 IO函数(商品期货扩展)

        传统商品期货扩展的IO功能

        • exchange.IO("status");

          返回true证明与CTP服务器行情与数据的两台服务器都连接正常

          while (!exchange.IO("status")) {
              Sleep(3000);
              LogStatus("正在等待与交易服务器连接, " + new Date());
          }
          
        • exchange.IO("wait");

          当前交易所有任何品种更新行情信息时才返回, 可带第二个参数(毫秒数)指定超时, 超时返回null, 正常返回EventTick结构。 exchange.IO("wait") 结合 exchange.IO("mode", 0) 函数使用(说明 exchange.IO("mode", 0) :立即返回模式, 如果当前还没有接收到交易所最新的行情数据推送, 就立即返回旧的行情数据,如果有新的数据就返回新的数据 )。这样配合使用就可以使程序在有最新行情时进行响应,执行程序逻辑。

          // 代码节选自 “商品期货交易类库 ”
          $.CTA = function(contractType, onTick, interval) {
              SetErrorFilter("login|ready|初始化")
              if (typeof(interval) !== 'number') {
                  interval = 500
              }
              exchange.IO("mode", 0)               // 切换 为立即返回模式,不会导致程序卡在获取行情的函数调用位置。
                                                   // 也不会因为一个品种 行情没有更新而导致程序等待。
              ...
          }
          // 队列 任务处理 代码块
          self.poll = function() {
              var processed = 0
              if (self.tasks.length > 0) {
                  _.each(self.tasks, function(task) {
                      if (!task.finished) {
                          processed++
                          self.pollTask(task)
                      }
                  })
                  if (processed == 0) {
                      self.tasks = []
                  }
              } else {
                  // wait for master market update
                  exchange.IO("wait")                // 此处使用 exchange.IO("wait") 等待任意品种更新行情。 
              }
              return processed
          }
          
        • exchange.IO("wait_any");

          同上, 但是指的是有任何一个交易所收到行情信息时就返回,EventTick里的Index指交易所索引

          // 用于 多交易所对象(多个期货公司前置服务器) 收集行情数据时。 
          
        • exchange.IO("wait_order");

          等待任意订单的交易信息, 返回一个Json结构{Index: 交易所索引, Nano: 事件纳秒级时间, Order: 订单信息} 超时返回json的null对像

        • exchange.IO("instruments");

          返回交易所所有的合约列表{合约名: 详情}字典形式, 只支持实盘

          Log("开始获取所有合约");
          var instruments = _C(exchange.IO, "instruments");
          Log("合约列表获取成功");
          var len = 0;
          for (var instrumentId in instruments) {
              len++;
          }
          Log("合约列表长度为:", len);
          
        • exchange.IO("products");

          返回交易所所有的产品列表{产品名: 详情}字典形式, 只支持实盘

        • exchange.IO("subscribed");

          返回已订阅行情的合约, 格式同上, 只支持实盘

        • exchange.IO("settlement");

          结算单查询, 不加第二个参数默认返回之前一个交易日的, 加参数如”20170317”指返回20170317的结算单, 只支持实盘

      • 2.6.6 StrDecode

        商品期货 CTP 协议中的汉字是GBK编码可用此函数解码

        详细例子参看以下:2.6.7

      • 2.6.7 IO函数调用CTP接口

        发明者量化的CTP(商品期货)终端提供了完整的全API实现, 当发明者平台的API满足不了你需要的功能时 可以用 exchange.IO 函数进行更深层的系统调用, 完全兼容官方的Api名称, 以几个简单的例子做为介绍

        • 查询投资者信息

          Log(exchange.IO("api", "ReqQryInvestor"))
          
        • 修改密码

          exchange.IO("api", "ReqUserPasswordUpdate", {BrokerID: "9999", UserID: "11111", OldPassword: "oldpass", NewPassword: "newpass"})
          
        • 复杂的例子

          function main() {
              // 如果再加一个参数值为false表示不等待返回值, 只发送请求
              // 第三个参数只需要填充需要的字段, 也可省略此参数, 如果类型为char,传长度为1的字符串即可
              var r = exchange.IO("api", "ReqQryProduct", {ProductID: "MA"}); 
              if (!r) { // CTP 未登陆的时候会失败
                  return
              }
              _.each(r, function(item) { // IO请求可能返回多个数据包, 所以以数组的形式返回
                  _.each(item, function(f) { // 便历数据包的所有数据类型, 一个数据包可能包含多个具体数据
                      // 具体数据类型的名称, 请参看CTP官方文档 http://www.sfit.com.cn/5_2_DocumentDown.htm
                      if (f.Name == 'CThostFtdcProductField') { // 取出来需要的数据, Name 为此数据的类型, Value 为此数据的值
                          f.Value.ProductName = StrDecode(f.Value.ProductName) // CTP中的汉字是GBK编码可用此函数解码
                          Log(f.Value) // 打印查询的的甲醇的信息
                      }
                  })
              });
          }
          
        • 查询结算单

          function main() {
              var r = exchange.IO("api", "ReqQrySettlementInfo", {TradingDay: "20190506"}); // 也可不指定日期
              var s = ''
              _.each(r, function(item) {
                  _.each(item, function(f) {
                      if (f.Name == 'CThostFtdcSettlementInfoField') {
                          s += f.Value.Content
                      }
                  })
              });
              Log(StrDecode(s));
          }
          
        • CTP 相关资料帖:

          资料地址:https://www.fmz.com/bbs-topic/3756

      • 2.6.8 传统商品期货

        传统商品期货API获取更多信息

        exchange.GetAccount();
        Log(exchange.GetRawJSON());//在GetAccount成功后调用, 获取更详细的账户信息, 可以用JSON.parse解析。 
        

        也支持GetTicker, GetDepth后的exchange.GetRawJSON(), 以及GetPosition与GetOrders,GetOrder这三个调用后的详细反馈数据。

        期货交易中Buy, Sell, CancelOrder和现货交易的区别

        Buy或Sell之前需要调用 SetDirection明确操作类型,如:

        exchange.SetDirection("sell");  
        exchange.Sell(1000, 2);
        exchange.SetDirection("buy"); 
        exchange.CancelOrder(123);
        

        商品期货支持自定义订单类型 (支持实盘,回测暂不支持)

        以后缀方式指定, 附加在_后面比如

        exchange.SetDirection("buy_ioc");
        exchange.SetDirection("sell_gtd-20170111"); // 交易所暂不支持这种类型
        
        后缀 意义 对应CTP原始值
        ioc 立即完成,否则撤销 THOST_FTDC_TC_IOC
        gfs 本节有效 THOST_FTDC_TC_GFS
        gfd 当日有效 THOST_FTDC_TC_GFD
        gtd 指定日期前有效 THOST_FTDC_TC_GTD
        gtc 撤销前有效 THOST_FTDC_TC_GTC
        gfa 集合竞价有效 THOST_FTDC_TC_GFA
    • 2.7 日志信息

      • 2.7.1 Log

        Log(message)

        保存一条信息到日志列表

        参数值:message可以是任意类型

        如果在字符串后面加上@字符则消息会进入推送队列, 推送到使用绑定的微信账号上(账户安全里绑定)(50条/小时, 1条/5秒 限制) 注意: 微信推送的信息不能重复!(否则只会推送1条。)

        如:

        # 注意:回测系统不支持微信推送!
        Log("微信你好 !@"); 或Log("微信你好, #ff0000@");
        

        Log支持打印base64编码后的图片, 以""开头, 以""结尾, 如:

        Log("`data:image/png;base64,AAAA`")
        

        Log支持直接打印Python的matplotlib.pyplot对象, 只要对象包含savefig方法就可以直接Log打印, 如:

        import matplotlib.pyplot as plt 
        def main(): 
            plt.plot([3,6,2,4,7,1]) 
            Log(plt)
        
      • 2.7.2 LogProfit

        LogProfit(Profit)

        记录盈利值,这个为总盈利的值,打印收益数值,并根据收益数值绘制收益曲线。

        参数值:profit为number类型

        LogProfit(10, '&')     # 可以以 字符 '&' 结尾,实现只绘制收益图表,不打印收益日志。
        
      • 2.7.3 LogProfitReset

        LogProfitReset()

        清空所有收益日志, 可以带一个数字参数, 指定保留的条数

      • 2.7.4 LogStatus

        LogStatus(Msg)

        此信息不保存到日志列表里, 只更新当前机器人的状态信息, 在日志上方显示, 可多次调用, 更新状态

        参数值:Msg可以为任意类型

        LogStatus('这是一个普通的状态提示'); 
        LogStatus('这是一个红色字体的状态提示 #ff0000'); 
        LogStatus('这是一个多行的状态信息\n我是第二行'); 
        

        LogStatus支持打印base64编码后的图片, 以""开头, 以""结尾, 如LogStatus(“data:image/png;base64,AAAA`”) LogStatus支持直接传入Python的matplotlib.pyplot对象, 只要对象包含savefig方法就可以传入LogStatus, 如:

        import matplotlib.pyplot as plt 
        def main():
            plt.plot([3,6,2,4,7,1])
            LogStatus(plt) 
        

        javascript

        var table = {type: 'table', title: '持仓信息', cols: ['列1', '列2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]}; 
        LogStatus('`' + JSON.stringify(table) + '`'); // JSON序列化后两边加上`字符, 视为一个复杂消息格式(当前支持表格) 
        LogStatus('第一行消息\n`' + JSON.stringify(table) + '`\n第三行消息'); // 表格信息也可以在多行中出现 
        LogStatus('`' + JSON.stringify([table, table]) + '`'); // 支持多个表格同时显示, 将以TAB显示到一组里 
        // 也可以构造一个按钮在表格中, 策略用GetCommand接收cmd属性的内容 
        var table = { 
            type: 'table', 
            title: '持仓操作', 
            cols: ['列1', '列2', 'Action'], 
            rows: [ 
                ['abc', 'def', {'type':'button', 'cmd': 'coverAll', 'name': '平仓'}], 
            ]
        }; 
        LogStatus('`' + JSON.stringify(table) + '`') 
        // 或者构造一单独的按钮 
        LogStatus('`' + JSON.stringify({'type':'button', 'cmd': 'coverAll', 'name': '平仓'}) + '`') 
        // 可以自定义按钮风格(bootstrap的按钮属性)
        LogStatus('`' + JSON.stringify({'type':'button', 'class': 'btn btn-xs btn-danger', 'cmd': 'coverAll', 'name': '平仓'}) + '`')
        

        合并LogStatus函数画出的表格内的单元格

        • 横向合并

          function main() {
              var table = { 
                  type: 'table', 
                  title: '持仓操作', 
                  cols: ['列1', '列2', 'Action'], 
                  rows: [ 
                      ['abc', 'def', {'type':'button', 'cmd': 'coverAll', 'name': '平仓'}], 
                  ]
              } 
              var ticker = exchange.GetTicker()
              table.rows.push([{body : JSON.stringify(ticker), colspan : 2}, "abc"])    // 添加一行数据,第一个和第二个单元格合并,并且输出 ticker 变量在 合并后的单元格内。
              LogStatus('`' + JSON.stringify(table) + '`')
          }
          
        • 纵向合并

          function main() {
              var table = { 
                  type: 'table', 
                  title: '持仓操作', 
                  cols: ['列1', '列2', 'Action'], 
                  rows: [ 
                      ['abc', 'def', {'type':'button', 'cmd': 'coverAll', 'name': '平仓'}], 
                  ]
              } 
          
              var ticker = exchange.GetTicker()
              var depth = exchange.GetDepth()
          
              table.rows.push([{body : JSON.stringify(ticker), colspan : 2}, "abc"])
              table.rows.push([{body : JSON.stringify(depth), rowspan : 3}, "第二格", "abc"])
              table.rows.push(["B1", "C1"])                                            // A1 被 上一行第一个单元格合并
              table.rows.push(["B2", "C2"])                                            // A2 被 上一行第一个单元格合并
              table.rows.push(["A3", "B3", "C3"])
              LogStatus('`' + JSON.stringify(table) + '`')
          }
          

          img

        C++

        #include <sstream>
        void main() {
            string name = "Jack";
            int age = 18;
        
            stringstream ss;
            string str_age;
            ss<<age;
            ss>>str_age;
            json tbl = R"({"type" : "table", "title" : "AAA", "cols" : ["Name", "Age"], "rows": []})"_json; // 使用 库 nlohmann/json
            tbl["rows"].push_back({name + "#FF0000", str_age + "#FF0000"});
            tbl["rows"].push_back({"Lucy", "23"});
            LogStatus("`"+tbl.dump()+"`");   // 更新 显示 状态栏。
        }
        

        img

        除了可以分页显示表格,也可以多个表格自上而下排列。

        function main(){
            var tab1 = {
                type : "table",
                title : "表格1",
                cols : ["1", "2"],
                rows : [],
            }
            var tab2 = {
                type : "table",
                title : "表格2",
                cols : ["1", "2", "3"],
                rows : [],
            }
            var tab3 = {
                type : "table",
                title : "表格3",
                cols : ["A", "B", "C"],
                rows : [],
            }
        
            tab1.rows.push(["jack", "lucy"])
            tab2.rows.push(["apple", "pen", "apple pen"])
            tab3.rows.push(["pineapple", "pen", "pen-pineapple-apple-pen"])
        
            LogStatus('`' + JSON.stringify(tab1) + '`\n' + 
                '`' + JSON.stringify(tab2) + '`\n' +
                '`' + JSON.stringify(tab3) + '`')
        
            Log("exit")
        }
        

        运行效果: img

        # 注意:
        # 策略机器人运行时,在机器人页面,如果翻看历史记录时, 状态栏会进入休眠状态,停止更新,
        # 只有日志在第一页的时候,状态栏数据才会刷新。
        
      • 2.7.5 EnableLog

        EnableLog(IsEnable)

        打开或者关闭订单和出错信息的日志记录

        参数值:isEnable为bool类型

      • 2.7.6 (画图)Chart

        Chart({…})

        参数为可以JSON序列化的HighStocks的Highcharts.StockChart参数, 比原生的参数增加一个__isStock属性, 如果指定__isStock: false, 则显示为普通图表

        # 注意:
        # 如果 设置 __isStock 属性为 false ,即使用的图表为: Highcharts 。
        # 如果 设置 __isStock 属性为 true , 使用的图表为: Highstocks (默认 __isStock 为 true)。
        

        返回对像可以调用add([series索引(如0), 数据])向指定索引的series添加数据, 调用reset()清空图表数据, reset可以带一个数字参数, 指定保留的条数

        可以调用add([series索引(如0), 数据, 此数据在series中的索引])来更改数据

        可以为负数, -1指最后一个, -2是倒数第二个, 如:

        chart.add([0, 13.5, -1]), 更改series[0].data的倒数第一个点的数据

        支持显示多个图表, 配置时只需传入数组参数即可如: var chart = Chart([{…}, {…}, {…}]), 比如图表一有两个series, 图表二有一个series, 图表三有一个series, 那么add时指定0与1序列ID代表更新图表1的两个序列的数据, add时指定序列ID为2指图表2的第一个series的数据, 指定序列3指的是图表3的第一个series的数据

        HighStocks: http://api.highcharts.com/highstock

        多图表显示相关的一些属性设置:

        范例: https://www.fmz.com/strategy/38203

        例如图表配置对象:

        var cfgA = {
            extension: {
                layout: 'single', // 不参于分组,单独显示, 默认为分组 'group'
                height: 300,      // 指定高度
                col: 8,           // 指定宽度占的单元值, 总值 为12
            },
            title: {
                text: '盘口图表'
            },
            xAxis: {
                type: 'datetime'
            },
            series: [{
                name: '买一',
                data: [],
            }, {
                name: '卖一',
                data: [],
            }]
        }
        var cfgB = {
            title: {
                text: '差价图'
            },
            xAxis: {
                type: 'datetime'
            },
            series: [{
                name: '差价',
                type: 'column',
                data: [],
            }]
        }
        
        var cfgC = {
            __isStock: false,
            title: {
                text: '饼图'
            },
            series: [{
                type: 'pie',
                name: 'one',
                data: [
                    ["A", 25],
                    ["B", 25],
                    ["C", 25],
                    ["D", 25],
                ]  // 指定初始数据后不需要用add函数更新, 直接更改图表配置就可以更新序列.
            }]
        };
        var cfgD = {
            extension: {
                layout: 'single',
                col: 8, // 指定宽度占的单元值, 总值 为12
                height: '300px',
            },
            title: {
                text: '盘口图表'
            },
            xAxis: {
                type: 'datetime'
            },
            series: [{
                name: '买一',
                data: [],
            }, {
                name: '卖一',
                data: [],
            }]
        }
        var cfgE = {
            __isStock: false,
            extension: {
                layout: 'single',
                col: 4,
                height: '300px',
            },
            title: {
                text: '饼图2'
            },
            series: [{
                type: 'pie',
                name: 'one',
                data: [
                    ["A", 25],
                    ["B", 25],
                    ["C", 25],
                    ["D", 25],
                ]
            }]
        };
        
        • cfgA.extension.layout 属性

          如果设置此属性,值为 “single” ,则图表不会叠加(不会以分页标签方式显示),会单独显示(平铺显示)。

        • cfgA.extension.height 属性

          此属性用于设置图表的高度,值可以为数值类型,或以"300px" 方式设置。

        • cfgA.extension.col 属性

          此属性用于设置图表的宽度,页面宽度一共划分为12个单元,设置8即该图表占用8个单元宽度。

          以上范例中图表配置对象,显示效果:

          img img

        • 图表配置对象上的数据直接修改图表配置,然后更新图表即可实现数据更新:

          例如范例中:

          cfgC.series[0].data[0][1] = Math.random() * 100;
          cfgE.series[0].data[0][1] = Math.random() * 100;
          // update实际上等于重置了图表的配置
          chart.update([cfgA, cfgB, cfgC, cfgD, cfgE]);
          

          通过add方法更新数据,例如给饼图增加一个项目。

          // 为饼图清加一个数点,add只能更新通过add方式添加的数据点, 内置的数据点无法后期更新
          chart.add(3, {
              name: "ZZ",
              y: Math.random() * 100
          });
          
        • 附带一个 使用Chart 函数的例子

        范例1:

        var chart = { // 这个 chart 在JS 语言中 是对象, 在使用Chart 函数之前我们需要声明一个配置图表的对象变量chart。
            __isStock: true,                                    // 标记是否为一般图表,有兴趣的可以改成 false 运行看看。
            tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},    // 缩放工具
            title : { text : '差价分析图'},                       // 标题
            rangeSelector: {                                    // 选择范围
                buttons:  [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}],
                selected: 0,
                inputEnabled: false
            },
            xAxis: { type: 'datetime'},                         // 坐标轴横轴 即:x轴, 当前设置的类型是 :时间
            yAxis : {                                           // 坐标轴纵轴 即:y轴, 默认数值随数据大小调整。
                title: {text: '差价'},                           // 标题
                opposite: false,                                // 是否启用右边纵轴
            },
            series : [                                          // 数据系列,该属性保存的是 各个 数据系列(线, K线图, 标签等..)
                {name : "line1", id : "线1,buy1Price", data : []},  // 索引为0, data 数组内存放的是该索引系列的 数据
                {name : "line2", id : "线2,lastPrice", dashStyle : 'shortdash', data : []}, // 索引为1,设置了dashStyle : 'shortdash' 即:设置 虚线。
            ]
        };
        function main(){
            var ObjChart = Chart(chart);  // 调用 Chart 函数,初始化 图表。
            ObjChart.reset();             // 清空
            while(true){
                var nowTime = new Date().getTime();   // 获取本次轮询的 时间戳,  即一个 毫秒 的时间戳。用来确定写入到图表的X轴的位置。
                var ticker = _C(exchange.GetTicker);  // 获取行情数据
                var buy1Price = ticker.Buy;           // 从行情数据的返回值取得 买一价
                var lastPrice = ticker.Last + 1;      // 取得最后成交价,为了2条线不重合在一起 ,我们加1
                ObjChart.add([0, [nowTime, buy1Price]]); // 用时间戳作为X值, 买一价 作为Y值 传入 索引0 的数据序列。
                ObjChart.add([1, [nowTime, lastPrice]]); // 同上。
                Sleep(2000);
            }
        }
        

        范例2

        var chart = {  // 用于初始化 图表的对象
            title: {text: "line数值触发 plotLines 值"},   // 图表标题
            yAxis: { // Y轴 相关 设置
                plotLines: [{   //  垂直于Y轴的 水平线, 用作触发线, 是一个结构数组, 可以设置多条触发线。
                    value: 0,   //  触发线的值,设置多少 这条线就在相应的数值位置显示。
                    color: 'red',  // 设置触发线的颜色
                    width: 2,      //  宽度
                    label: {       //  显示的标签
                        text: '触发值',    //标签文本
                        align: 'center'   //标签位置  居中
                    },
                }],
            },
            xAxis: {type: "datetime"},  // X轴相关设置,  这里设置类型是 时间轴
            series: [{name: "sin", type: "spline", data: []},
                     {name: "cos", type: "spline", data: []}]  // 这个是比较重要的数据系列,可以设置多个数据系列,根据数组索引控制
        };
        function main(){
             var pi = 3.1415926535897;             //  圆周率
            var time = 0;                         //  用于记录时间戳的变量
            var angle = 0;                        //  角度
            var y = 0;                            //  坐标y值  ,  用于接收 正弦值、余弦值
            var objChart = Chart(chart);          //  调用API 接口 用chart 对象初始化 图表
            objChart.reset();                     //  初始清空图表
            chart.yAxis.plotLines[0].value = 1;   //  设置触发线的值为1
            while(true){                         //  循环
                time = new Date().getTime();     //   获取当前时刻的时间戳
                y = Math.sin(angle * 2 * pi / 360);   // 每 500ms 角度 angle 增加 5 度,计算正弦值。
                objChart.add(0, [time, y]);           //  把计算出来的y 值写入图表 相应索引的数据系列 add 函数第一个参数 为 指定的索引
                y = Math.cos(angle * 2 * pi / 360);   //  计算余弦值
                objChart.add(1, [time, y]);
                angle += 5;                           // 增加5度
                Sleep(5000);                          // 暂停5秒  ,以免画图太频繁,数据增长过快。
            }
        }
        

        C++ 版本 Chart 函数范例

        Chart(R"EOF(string_Tab)EOF"); string_Tab 字符串

        // string_Tab : 
        {
            "chart":{
                "type":"line"
            },
            "title":{
                "text":"简单图表"
            },
            "xAxis":{
                "title":{
                    "text":"Date"
                }
            },
            "yAxis":{
                "title":{
                    "text":"Number"
                }
            },
            "series":[
                {
                    "name":"number",
                    "data":[]
                }
            ]
        }
        

        范例代码:

        Chart c = Chart(R"EOF({"chart":{"type":"line"},"title":{"text":"简单图表"},"xAxis":{"title":{"text":"Date"}},"yAxis":{"title":{"text":"Number"}},"series":[{"name":"number","data":[]}]})EOF");
        c.reset();
        for (size_t i = 0; i < 10; i++) {
            // sprintf比如int64在32位与64位下有不同的参数, 所以最好跟平台有关的类型用toString变成字符串再传进去
            c.add(0, format("[%s, %d]", toString(Unix() + i).c_str(), rand() % 100));
        }
        

        img

      • 2.7.7 LogReset

        LogReset()

        清除日志,可以传入一个参数,指定保留最近日志条数,清除其余日志。每次启动的启动日志算一条,所以如果不传入参数, 并且策略起始时没有日志输出,就会完全不显示日志,等待托管者日志回传。(并非异常情况) 无返回值

        LogReset(10)    // 保留最近10条日志,清除其余日志。
        
      • 2.7.8 LogVacuum

        LogVacuum()

        回收 SQLite 删除数据时,占用的空间。

        原因如下: img

    • 2.8 全局函数

      • 2.8.1 Version

        Version()

        返回系统当前版本号, 字符串值, 如3.0

        返回值:string类型

      • 2.8.2 Sleep

        Sleep(Millisecond)

        休眠函数,使程序暂停一段时间

        参数值:Millisecond为number类型

        参数为毫秒数,如Sleep(1000)为休眠一秒

      • 2.8.3 IsVirtual

        IsVirtual()

        判断是否是模拟回测

        返回值:bool类型

        模拟回测状态返回true,实盘返回false

      • 2.8.4 Mail

        Mail(smtpServer, smtpUsername, smtpPassword, mailTo, title, body)

        发送邮件函数

        参数值:都为string类型

        返回值:bool类型,发送成功返回true

        smtpServer为发送邮箱smtp,smtpUsername为邮箱账号,smtpPassword为邮箱密码,mailTo为接受邮箱账号,title为标题,body为内容。例如:

        function main(){
            Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
        }
        

        注意:

        # 阿里云服务器可能会封一些端口,导致邮件无法发出。
        # 如需更改端口,可以直接在第一个参数中加入端口号:
        # 如: qq的smtp.qq.com:587  ,该端口测试可用。
        # 
        # 如果 出现 报错: unencryped connection , 需要修改 Mail 函数 smtpServer参数为:
        # 格式 ssl://xxxxx.com:xxx     举例 QQ邮箱的 SMTP 的 ssl 方式: ssl://smtp.qq.com:465
        # 或者:
        # 格式 smtp://xxxxx.com:xxx 
        

        img

      • 2.8.5 SetErrorFilter

        SetErrorFilter(RegEx)

        错误信息过滤

        参数值:string类型

        被此正则表达式匹配的错误将不上传到日志系统, 可多次调用设置多个 (被过滤的日志,不写入 托管者 目录下 logs/robot 内的对应机器人ID 的数据库文件,防止频繁报错导致数据库文件膨胀。)

        SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused");
        
      • 2.8.6 GetPid

        GetPid()

        返回机器人进程ID

        返回值:string类型

        function main(){
            var id = GetPid();
            Log(id);
        }
        
      • 2.8.7 GetLastError

        GetLastError()

        获取最近一次出错信息,一般无需使用,因为程序会把出错信息自动上传到日志系统

        返回值:string类型

        function main(){
            exchange.GetOrder("123");//因为不存在编号为123的订单,所以会出错
            var error = GetLastError();
            Log(error);
        }
        
      • 2.8.8 GetCommand

        GetCommand() 获取交互命令(utf-8)

        获取策略交互界面发来的命令并清空, 没有命令则返回null, 返回的命令格式为 “按钮名称:参数”, 如果没有参数, 则命令就是按钮名称

        function main(){
            while(true) { 
                var cmd = GetCommand(); 
                if (cmd) { 
                    Log(cmd);
                } 
                Sleep(1000); 
            }
        }
        
      • 2.8.9 Dial

        Dial(Address, Timeout)

        原始的Socket访问, 支持tcp, udp, tls, unix 协议

        参数值:Address为string类型,填入地址,TimeOut为超时时间,超时,Dial函数返回空值,单位:秒。

        Address 参数详细说明

        参数说明
        设置Dial功能的参数 在正常的地址:wss://real.okex.com:10441/websocket?compress 后以 “|” 符号分隔,如果参数字符串中有\|字符,则以"||“作为分隔符号。各个参数之间用”&"连接,例如ss5代理和压缩参数一起设置:Dial(“wss://baidu.com/stream|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv”)
        用于ws协议时,数据压缩相关的参数:compress=参数值 compress为压缩方式,compress 参数,可选 gzip_raw , gzip 等。OKEX 的 gzip 方式非标准 gzip。 所以需要使用扩展的方式 : gzip_raw,即在分隔符 “|” 后添加设置 compress=gzip_raw , 用 “&” 符号和下一个mode参数分隔。
        用于ws协议时,数据压缩相关的参数:mode=参数值 mode为模式,可选 dual , send , recv 三种。dual 为双向,发送压缩数据,接收压缩数据。send 为发送压缩数据。recv 为接收压缩数据,本地解压缩。
        用于设置socks5代理的相关参数:proxy=参数值 proxy为ss5代理设置,参数值格式:socks5://name:pwd@192.168.0.1:1080 ,name为ss5 服务端 用户名,pwd为ss5 服务端 登录密码,1080为ss5服务的端口
        用于ws协议时,设置底层自动重连相关的参数:reconnect=参数值 reconnect为是否设置重连,reconnect=true 为启用重连,不设置默认不重连
        用于ws协议时,设置底层自动重连相关的参数:interval=参数值 interval为重试时间间隔,单位毫秒,interval=10000 为重试间隔10秒,不设置默认1秒,即 interval=1000
        用于ws协议时,设置底层自动重连相关的参数:payload=参数值 payload为ws重连时需要发送的订阅消息,例如:payload=okok
        function main(){
            var client = Dial("tls://www.baidu.com:443"); // Dial支持tcp://, udp://, tls://, unix:// 协议, 可加一个参数指定超时的秒数
            if (client) {
                client.write("GET / HTTP/1.1\nConnection: Closed\n\n"); // write可再跟一个数字参数指定超时, write返回成功发送的字节数
                while (true) {
                    var buf = client.read();// read可再跟一个数字参数指定超时, 单位:毫秒。 返回null指出错或者超时或者socket已经关闭
                    if (!buf) {
                         break;
                    }
                    Log(buf);
                }
            client.close();
            }
        }
        
          read函数支持以下参数:
              不传参数指阻塞到有消息就返回, 如`ws.read()`
              毫秒指定消息等待超时, 如`ws.read(2000)`指定超时为两秒
              以下两个参数只对websocket有效
              `-1` 指不管有无消息, 立即返回, 如`ws.read(-1)`
              `-2` 指不管有无消息, 立即返回, 但只返回最新的消息, 缓冲区的消息丢弃 如`ws.read(-2)`
        

        说明机制: read函数缓冲区说明: ws协议推送的来的数据,如果在策略read函数调用之间时间间隔过长,就可能造成数据累积,这些数据储存在缓冲区。 缓冲区数据结构为队列,上限2000个。超出2000后,最新的数据进入缓冲区,最旧的数据清除掉。

        read函数参数: 无参数 参数:-1 参数:-2 参数:2000,单位是ms
        缓冲区已有数据 立即返回最旧数据 立即返回最旧数据 立即返回最新数据 立即返回最旧数据
        缓冲区无数据 阻塞到有数据时返回 立即返回 null 立即返回 null 等待 2000ms,无数据返回null, 有数据则返回
        ws连接断开,底层重连时 read() 函数返回 空字符串,即: “” , write() 函数返回 0 ,检测到该情况,可以使用 close() 函数关闭连接,如果设置了自动重连则不用关闭,系统底层会自动重连。

        支持 wss (WebSocket) 协议

        JS策略范例:

        function main() {
            LogStatus("正在连接...");
            var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
            if (!client) {
                Log("连接失败, 程序退出");
                return
            }
            Log("连接成功, 断线低层会自动重连")
            while (true) {
                var buf = client.read() // read只返回调用read之后获取的数据
                if (!buf) {
                    break;
                }
                var table = {
                    type: 'table',
                    title: '行情图表',
                    cols: ['币种', '最高', '最低', '买一', '卖一', '最后成交价', '成交量', '更新时间'],
                    rows: [],
                };
                var obj = JSON.parse(buf);
                _.each(obj, function(ticker) {
                    table.rows.push([ticker.s, ticker.h, ticker.l, ticker.b, ticker.a, ticker.c, ticker.q, _D(ticker.E)])
                });
                LogStatus('`' + JSON.stringify(table) + '`')
            }
            client.close();
        }
        

        范例代码:

        function main(){
            // wss://real.okex.com:10441/websocket
            // websocket.send("{'event':'addChannel','channel':'ok_sub_spot_X_ticker'}");
            /*
            OKEx通过心跳机制解决这个问题。客户端每30秒发送一次心跳数据:{'event':'ping'},
            服务器会响应客户端:{"event":"pong"}以此来表明客户端和服务端保持正常连接。
            如果客户端未接到服务端响应的心跳数据则需要客户端重新建立连接。
            */
        
            var ws = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")
            if(ws){
                ws.write("{'event':'addChannel','channel':'ok_sub_spot_btc_usdt_ticker'}")
                var pingCyc = 1000 * 20
                var lastPingTime = new Date().getTime()
                while(1){
                    var nowTime = new Date().getTime()
                    var ret = ws.read()
                    Log("ret:", ret)
                    if(nowTime - lastPingTime > pingCyc){
                        var retPing = ws.write("{'event':'ping'}")
                        lastPingTime = nowTime
                        Log("发送 :{'event':'ping'} ", "#FF0000")
                    }
                    LogStatus("当前时间:", _D())
                    Sleep(1000)
                }
                ws.close() 
            }
        }
        
      • 2.8.10 HttpQuery

        HttpQuery(Url, PostData, Cookies, Headers, IsReturnHeader)

        网络URL访问

        参数值:都为string类型

        # 注意:
        # HttpQuery 函数只支持 JavaScript 语言
        # Python 语言 可以使用 urllib 库 ,直接发送 http 请求。
        

        获取一个Url的返回内容, 如果第二个参数PostData为字符串a=1&b=2&c=abc形式,就以POST方式提交,其它PUT等方式提交{method:'PUT', data:'a=1&b=2&c=abc'}

        PostData 也可以是 JSON 字符串。

        Cookies 这个参数形式为: a=10; b=20 ,各参数用分号;间隔 Headers 这个参数形式为: User-Agent: Mobile\nContent-Type: text/html各参数用换行符\n间隔。

        第二个参数PostData可以自定义方法比如:

        HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc'})
        # 注意: 如果需要给 HttpQuery 函数 设置超时时间,可以在 {method:'PUT', data:'a=1&b=2&c=abc'} 加入 timeout属性(默认60秒)
        HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc', timeout:1000})
        # 设置 1秒钟 超时。
        

        传递Cookie字符串需要第三个参数, 但不需要POST请将第二个参数置为null

        模拟测试的时候因为无法模拟访问URL, 函数就返回固定字符串 Dummy Data

        可以用此接口发送短信, 或者与其它API进行交互

        HttpQuery("http://www.baidu.com"); // Get 
        HttpQuery("http://www.163.com", "a=1&b=2&c=abc"); // Post 
        HttpQuery("http://www.baidu.com", null, "a=10; b=20", "User-Agent: Mobile\nContent-Type: text/html", true);  
        // will return {Header: HTTP Header, Body: HTML}
        

        访问OKEX不需要签名的API的例子,返回值为JSON字符串,可用JSON.parse()函数解析。

        img

        function main(){
            var CNY_Rate = HttpQuery("https://www.okex.com/api/v1/exchange_rate.do")
            Log("CNY_Rate 类型:", typeof(CNY_Rate)) 
        }
        
        • HttpQuery 函数 使用代理设置

          HttpQuery("socks5://127.0.0.1:8889/http://www.baidu.com/")   
          // 本次设置代理并发送http请求,无用户名,无密码,此次 http 请求 会通过代理 发送。
          
          HttpQuery("socks5://username:password@127.0.0.1:8889/http://www.baidu.com/")   
          // 本次设置代理并发送http请求,输入用户名 和 密码。
          
          // 仅 HttpQuery 当前调用生效,之后再次调用 HttpQuery("http://www.baidu.com") 这样不会使用代理。
          
      • 2.8.11 Hash

        Hash(Algo, OutputAlgo, Data)

        支持 md5/sha256/sha512/sha1 的哈希计算, 只支持实盘

        参数值:都为string类型

        第二个参数可设置为raw/hex/base64, 分别指输出加密后的 原始内容/hex编码过的/base64编码过的

        function main(){
            Log(Hash("md5", "hex", "hello")); 
            Log(Hash("sha512", "base64", "hello"));
        }
        
      • 2.8.12 HMAC

        HMAC(Algo, OutputAlgo, Data, Key)

        支持 md5/sha256/sha512/sha1 的HMAC加密计算, 只支持实盘

        参数值:都为string类型

        第二个参数可设置为raw/hex/base64, 分别指输出加密后的 原始内容/hex编码过的/base64编码过的

        function main(){
            Log(HMAC("md5", "hex", "hello", "pass")); 
            Log(HMAC("sha512", "base64", "hello", "pass"));
        }
        
      • 2.8.13 UnixNano

        UnixNano()

        返回纳秒级时间戳,如果需要获取毫秒级时间戳,可以使用如下代码:

        var time = UnixNano() / 1000000; Log(_N(time, 0));

      • 2.8.14 Unix

        Unix()

        返回秒级别时间戳。

        uint64_t t = Unix();       // C++  Unix()   : 1513233948 , 秒级别  
        Log(t);
        
      • 2.8.15 GetOS

        GetOS()

        返回托管者 所在 系统的 信息。

        Log("GetOS:", GetOS())
        

        在 MAC 操作系统 下运行的托管者。 日志输出: GetOS: darwin/amd64 , darwin : MAC 系统的 名称。

      • 2.8.16 MD5

        MD5(string)

        参数值:string 类型

        Log("MD5", MD5("hello world"))
        

        日志输出: MD5 5eb63bbbe01eeed093cb22bb8f5acdc3

    • 2.9 内置函数

      • 2.9.1 _G

        _G(K, V)

        可保存的全局字典

        KV表, 永久保存在本地文件, 每个机器人单独一个数据库, 重启或者托管者退出后一直存在K必须为数字或者字符串, 不区分大小写, V可以为任何可以JSON序列化的内容

        function main(){
            _G("num", 1); // 设置一个全局变量num, 值为1 s
            _G("num", "ok"); // 更改一个全局变量num, 值为字符串ok 
            _G("num", null); // 删除全局变量 num 
            _G("num"); // 返回全局变量num的值 
            _G(); // 返回当前机器人的ID 
            _G(null); // 删除所有全局变量
        }
        
      • 2.9.2 _D

        _D(timestamp, fmt)

        返回指定时间戳

        参数值: timestamp 为数值类型,毫秒数。 fmt为string类型 ,fmt 默认为:yyyy-MM-dd hh:mm:ss

        返回值:string类型

        返回指定时间戳(ms)字符串, 不传任何参数就返回当前时间,如_D(),或者_D(1478570053241), 默认格式为yyyy-MM-dd hh:mm:ss

        function main(){
            var time = _D();
            Log(time);
        }
        
      • 2.9.3 _N

        _N(num, precision)

        格式化一个浮点数

        参数值,num为number类型,precision为整型number

        返回值:number类型

        例如_N(3.1415, 2),将删除小数点两位以后的值,返回3.14

        function main(){
            var i = 3.1415;
            Log(i);
            var ii = _N(i, 2)
            Log(ii);
        }
        

        如果需要将小数点左边的N个位数都变为0,可以这么写:

        function main(){
            var i = 1300;
            Log(i);
            var ii = _N(i, -3)
            Log(ii); //查看日志得知为1000
        }
        
      • 2.9.4 _C

        _C(function, args…)

        重试函数

        会一直调用指定函数到成功返回(函数返回null或者false会重试),比如_C(exchange.GetTicker), 默认重试间隔为3秒, 可以调用_CDelay函数来控制重试间隔,比如_CDelay(1000), 指改变_C函数重试间隔为1秒,建议

        • exchange.GetTicker()
        • exchange.GetDepth()
        • exchange.GetTrade()
        • exchange.GetRecords()
        • exchange.GetAccount()
        • exchange.GetOrders()
        • exchange.GetOrder() 都通过_C来调用,以防出错。
        function main(){
            var ticker = _C(exchange.GetTicker);
            var depth = _C(exchange.GetDepth);
            Log(ticker);
            Log(depth);
        }
        

        对于有参数的函数,使用 _C 容错时:

        function main(){
            var records = _C(exchange.GetRecords, PERIOD_D1)
            Log(records)
        }
        

        也可以用于自定义函数:

        var test = function(a, b){
            var time = new Date().getTime() / 1000
            if(time % b == 3){
                Log("符合条件!", "#FF0000")
                return true
            }
            Log("重试!", "#FF0000")
            return false
        }
        
        function main(){
            var ret = _C(test, 1, 5)
            Log(ret)
        }
        
      • 2.9.5 _T

        Log(_T("当前语言|Current language"), _T("英语|English"))    // 打印 _T 函数的返回值时,会根据当前 发明者平台(FMZ.COM)网站设置的语言,自动显示为英语或者中文。
        
      • 2.9.6 _Cross

        _Cross(arr1, arr2)

        返回数组arr1与arr2的交叉周期数. 正数为上穿周期, 负数表示下穿的周期, 0指当前价格一样

        参数值:number数组

        具体使用说明:内置函数 _Cross 分析 及 使用说明

      • 2.9.7 自定义颜色

        每个消息字符串都可以用"#ff0000"这样的RGB值结尾, 代表需要显示的前景色, 如果为#ff0000112233这样的格式, 则后六后代表背景色

        颜色十六进制图 img

        Log("红色", "#FF0000")
        
    • 2.10 网络设置

      • 2.10.1 SetProxy

        切换为代理服务器 访问交易所 该函数 无返回值(用变量获取,获取的是 undefined),如果代理设置失败,在调用接口时,会返回 空值。 仅限 rest 协议

        • 每个交易所对象(exchanges[n])可以设置一个代理,设置代理后,访问交易所接口都会通过代理去访问。

          // 以主交易所对象 exchange 即:第一个添加的交易所对象 , 即:exchanges[0] 为例。
          exchange.SetProxy("socks5://127.0.0.1:8889")                      // 设置代理,无用户名,无密码。
          exchange.SetProxy("socks5://username:password@127.0.0.1:8889")    // 设置代理,输入 用户名 和 密码 
          exchange.SetProxy("")                                            // 切换为正常模式,不使用代理。
          
      • 2.10.2 SetTimeout

        仅限 rest 协议,用于设置 rest 请求时的超时时间,只用设置一次即可生效。 例如:exchange.SetTimeout(3000) , 设置 exchange 交易所对象 ,发送 rest 请求 开始 计时,超过3 秒,超时返回 null 。

        # 注意:
        # 参数 是 毫秒, 1000毫秒 等于 1秒
        # 只用设置一次。
        # 仅限 rest 协议。
        
    • 2.11 C++ 策略编写特殊事项

      • C++ 编写策略 和 JavaScript 编写策略 区别

        FMZ API 接口返回 数据的区别 举例 exchange.GetTicker() 获取行情 API:

        • JavaScript exchange.GetTicker() 返回一个 对象,如果调用失败(交易所服务器问题、网络问题 等等)返回 null 。

          var ticker = exchange.GetTicker()
          if (ticker){                          // 判断 exchange.GetTicker 函数是否调用失败,返回null 。
              Log(ticker)
          }
          
        • C++ exchange.GetTicker() 返回一个 对象,如果调用失败(…) 返回的还是一个对象,和正常返回的对象是通过一个属性来区别。

          auto ticker = exchange.GetTicker();
          if (ticker.Valid) {                   // 判断 exchange.GetTicker 函数是否调用失败,
                                                // 返回的对象中 Valid 属性是否是 false
              Log(ticker);
          }
          
      • C++ 策略中的 main 函数 与 标准 C11 中 main 函数的区别

        C11 中的 C++ 程序 入口函数 main() 返回值 为 int 类型,在 FMZ 的 C++ 策略中, 策略的启动函数也是 main() 函数,不过这两者并非是同一个函数,只是同名而已。并且 FMZ 的 C++ 策略中 main() 函数 的返回值 是 void 类型。

        void main() {
            if (!Test("c++")) {
                Panic("请下载最新版本托管者");
            }
            // 所有的对像返回用Valid来判断是否有效
            LogProfitReset();
            LogReset();
            Log(_N(9.12345, 2));
            Log("use _C", _C(exchange.GetTicker), _C(exchange.GetAccount));
        }
        

  • 3. 指标函数

    调用指标函数时需要加上TA.或者talib.前缀

    使用例子:

    function main(){
        var records = exchange.GetRecords();
        var macd = TA.MACD(records);
        var atr = TA.ATR(records, 14);
        // 打印出最后一排值
        Log(macd[0][records.length-1], macd[1][records.length-1],
        macd[2][records.length-1]);
        Log(atr[atr.length-1]);
        Log(talib.MACD(records));
        Log(talib.MACD(records, 12, 26, 9));
        Log(talib.OBV(records));
        // talib也可以传入数字数组, 依次传入即可
        // 如: OBV(Records[Close],Records[Volume]), 需要Close, Volume两个数组参数
        Log(talib.OBV([1,2,3], [7.1, 6.2, 3,3]));
        // 也可以直接传入包含Close, Volume属性的records数组
        Log(talib.OBV(records));
        Log(TA.Highest(records, 30, 'High'));
        Log(TA.Highest([1,2,3,4], 0));
        // 针对Python, 系统扩展了GetRecords返回的数组的属性, 增加了Open, High, Low, Close, Volume, 方便talib调用, 如
        talib.MACD(records.Close); // Close属性会返回records所有成员的Close属性做为numpy数组传给talib, 其它的属性同样这样调用
        math.std([1,2,3,4,5]);
        _.map([1, 2, 3], function(num){ return num * 3; });
    }
    

    以下参数中的数据均为exchange.GetRecoreds(Period)获得的数据。 注意records长度,当长度不足时将返回null。

    • 3.1 TA - 常用指标优化库

      • MACD,指数平滑异同平均线

        TA.MACD(数据, 快周期, 慢周期, 信号周期) 默认参数为(12, 26, 9), 返回二维数组, 分别是[DIF, DEA, MACD]

        function main(){
            var records = exchange.GetRecords(PERIOD_M15);//可以填入不同k线周期,比如PERIOD_M1,PERIOD_M30,PERIOD_H1......
            var macd = TA.MACD(records, 12, 26, 9);
            Log("DIF:", macd[0], "DEA:", macd[1], "MACD:", macd[2]);
            //观看日志可得知返回三个数组,分别对应DIF,DEA,MACD。
        }
        
      • KDJ, 随机指标

        TA.KDJ(数据, 周期1, 周期2, 周期3) 默认参数为(9, 3, 3), 返回二维数组, 分别是[K, D, J]

        function main(){
            var records = exchange.GetRecords(PERIOD_M15);
            var kdj = TA.KDJ(records, 9, 3, 3);
            Log("k:", kdj[0], "d:", kdj[1], "j:", kdj[2]);
        }
        
      • RSI, 强弱指标

        TA.RSI(数据, 周期) 默认参数为14, 返回一个一维数组

        function main(){
            var records = exchange.GetRecords(PERIOD_M30);
            var rsi = TA.RSI(records, 14);
            Log(rsi);
        }
        
      • ATR, 平均真实波幅

        TA.ATR(数据, 周期) ATR(数据, 周期), 默认参数为14, 返回一个一维数组

        function main(){
            var records = exchange.GetRecords(PERIOD_M30);
            var atr = TA.ATR(records, 14);
            Log(atr);
        }
        
      • OBV, 能量潮

        TA.OBV(数据) 返回一个一维数组

        function main(){
            var records = exchange.GetRecords(PERIOD_M30);
            var obv = TA.OBV(records);
            Log(obv);
        }
        
      • MA, 移动平均线

        TA.MA(数据, 周期) MA(数据, 周期), 默认参数为9, 返回一个一维数组

        function main(){
            var records = exchange.GetRecords(PERIOD_M30);
            var ma = TA.MA(records, 14);
            Log(ma);
        }
        
      • EMA, 指数平均数指标

        TA.EMA(数据, 周期) 指数平均数指标 默认参数为9, 返回一个一维数组

        var records = exchange.GetRecords()
        if (records && records.length > 9) {
            var ema = TA.EMA(records, 9)          // K线bar 数量满足指标计算周期。
        }
        
      • BOLL, 布林带

        TA.BOLL(数据, 周期, 乘数) BOLL(数据, 周期, 乘数), 布林线指标, 默认参数为(20, 2) 返回一个二维数组[上线, 中线, 下线]

        var records = exchange.GetRecords()
        if(records && records.length > 20){
            var boll = TA.BOLL(records, 20, 2)
            var upLine = boll[0]
            var midLine = boll[1]
            var downLine = boll[2]
        }
        
      • Alligator, Alligator Indicator

        TA.Alligator(数据, 下颚周期,牙齿周期,上唇周期) Alligator(数据, 下颚周期,牙齿周期,上唇周期), 鳄鱼线指标, 默认参数为(13,8,5) 返回一个二维数组[下颚,牙齿,上唇]

      • CMF, Chaikin Money Flow

        TA.CMF(数据, 周期) 蔡金货币流量指标 CMF(数据, 周期), 默认周期参数为20, 返回一个一维数组

      • Highest, 周期最高价

        TA.Highest(数据, 周期, 属性) 返回最近周期内的最大值(不包含当前Bar), 如TA.Highest(records, 30, ‘High’), 如果周期为0指所有, 如属性不指定则视数据为普通数组. 返回一个价格(数值类型)

      • Lowest, 周期最低价

        TA.Lowest(数据, 周期, 属性), 返回最近周期内的最小值(不包含当前Bar), 如TA.Lowest(records, 30, ‘Low’), 如果周期为0指所有, 如属性不指定则视数据为普通数组. 返回一个价格(数值类型)

        C++ 策略中 Highest 、Lowest 的使用 需注意,Highest 、Lowest 函数各自只有2个参数,并且第一个参数,传入的不是 auto r = exchange.GetRecords()函数返回值,需要调用 r 的方法 传入 具体属性数据,例如:传入 r.Close() 收盘价数据。

        # Close、High、Low、Open、Volume  如同 r.Close() 调用方式。
        
        void main() { 
            Records r;
            r.Valid = true;
            for (auto i = 0; i < 10; i++) {
                Record ele;
                ele.Time = i * 100000;
                ele.High = i * 10000;
                ele.Low = i * 1000;
                ele.Close = i * 100;
                ele.Open = i * 10;
                ele.Volume = i * 1;
                r.push_back(ele);
            }
        
            for(int j = 0; j < r.size(); j++){
                Log(r[j]);
            }
        
            auto highest = TA.Highest(r.Close(), 8);   // 注意: 第一个参数 传入的不是 r ,需要调用 r.Close()    
            Log(highest);                     
        }
        
    • 3.2 附带的第三方库

    • 3.3 talib库里面的函数指标

      以下函数的参数中Records[Close]代表传入的k线数据中的收盘价 Array()代表数组,Array(outInteger)代表返回的是整型数据数组

      CCI 指标调用范例python代码

      import talib
      def main():
          records = exchange.GetRecords()
          cci = talib.CCI(records.High, records.Low, records.Close, 14)   # 14 这个参数 可以 缺省。
          Log(cci)
      

      Pattern Recognition 模式识别

      指标 描述
      CDL2CROWS Two Crows (K线图–两只乌鸦)
      CDL2CROWS(Records[Open,High,Low,Close]) = Array(outInteger)
      CDL3BLACKCROWS Three Black Crows (K线图–3只黑乌鸦)
      CDL3BLACKCROWS(Records[Open,High,Low,Close]) = Array(outInteger)
      CDL3INSIDE Three Inside Up/Down (K线图:3内上下震荡)
      CDL3INSIDE(Records[Open,High,Low,Close]) = Array(outInteger)
      CDL3LINESTRIKE Three-Line Strike (K线图:3线震荡)
      CDL3LINESTRIKE(Records[Open,High,Low,Close]) = Array(outInteger)
      CDL3OUTSIDE Three Outside Up/Down (K线图:3外下震荡)
      CDL3OUTSIDE(Records[Open,High,Low,Close]) = Array(outInteger)
      CDL3STARSINSOUTH Three Stars In The South (K线图:南方三星)
      CDL3STARSINSOUTH(Records[Open,High,Low,Close]) = Array(outInteger)
      CDL3WHITESOLDIERS Three Advancing White Soldiers (K线图:三白兵)
      CDL3WHITESOLDIERS(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLABANDONEDBABY Abandoned Baby (K线图:弃婴)
      CDLABANDONEDBABY(Records[Open,High,Low,Close],Penetration = 0.3) = Array(outInteger)
      CDLADVANCEBLOCK Advance Block (K线图:推进)
      CDLADVANCEBLOCK(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLBELTHOLD Belt-hold (K线图:带住)
      CDLBELTHOLD(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLBREAKAWAY Breakaway (K线图:分离)
      CDLBREAKAWAY(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLCLOSINGMARUBOZU Closing Marubozu (K线图:收盘光头光脚)
      CDLCLOSINGMARUBOZU(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLCONCEALBABYSWALL Concealing Baby Swallow (K线图:藏婴吞没形态)
      CDLCONCEALBABYSWALL(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLCOUNTERATTACK Counterattack (K线图:反击)
      CDLCOUNTERATTACK(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLDARKCLOUDCOVER Dark Cloud Cover (K线图:乌云盖)
      CDLDARKCLOUDCOVER(Records[Open,High,Low,Close],Penetration = 0.5) = Array(outInteger)
      CDLDOJI Doji (K线图:十字星 )
      CDLDOJI(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLDOJISTAR Doji Star (K线图:十字星)
      CDLDOJISTAR(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLDRAGONFLYDOJI Dragonfly Doji (K线图:蜻蜓十字星)
      CDLDRAGONFLYDOJI(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLENGULFING Engulfing Pattern (K线图:吞没)
      CDLENGULFING(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLEVENINGDOJISTAR Evening Doji Star (K线图:黄昏十字星)
      CDLEVENINGDOJISTAR(Records[Open,High,Low,Close],Penetration = 0.3) = Array(outInteger)
      CDLEVENINGSTAR Evening Star (K线图:黄昏之星)
      CDLEVENINGSTAR(Records[Open,High,Low,Close],Penetration = 0.3) = Array(outInteger)
      CDLGAPSIDESIDEWHITE Up/Down-gap side-by-side white lines (K线图:上/下间隙并排的白色线条)
      CDLGAPSIDESIDEWHITE(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLGRAVESTONEDOJI Gravestone Doji (K线图:墓碑十字线)
      CDLGRAVESTONEDOJI(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLHAMMER Hammer (K线图:锤)
      CDLHAMMER(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLHANGINGMAN Hanging Man (K线图:吊人)
      CDLHANGINGMAN(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLHARAMI Harami Pattern (K线图:阴阳线)
      CDLHARAMI(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLHARAMICROSS Harami Cross Pattern (K线图:交叉阴阳线)
      CDLHARAMICROSS(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLHIGHWAVE High-Wave Candle (K线图:长脚十字线 )
      CDLHIGHWAVE(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLHIKKAKE Hikkake Pattern (K线图:陷阱)
      CDLHIKKAKE(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLHIKKAKEMOD Modified Hikkake Pattern (K线图:改良的陷阱)
      CDLHIKKAKEMOD(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLHOMINGPIGEON Homing Pigeon (K线图:信鸽)
      CDLHOMINGPIGEON(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLIDENTICAL3CROWS Identical Three Crows (K线图:相同的三只乌鸦)
      CDLIDENTICAL3CROWS(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLINNECK In-Neck Pattern (K线图:颈纹)
      CDLINNECK(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLINVERTEDHAMMER Inverted Hammer (K线图:倒锤)
      CDLINVERTEDHAMMER(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLKICKING Kicking (K线图:踢)
      CDLKICKING(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLKICKINGBYLENGTH Kicking - bull/bear determined by the longer marubozu (K线图:踢牛/踢熊)
      CDLKICKINGBYLENGTH(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLLADDERBOTTOM Ladder Bottom (K线图:梯底)
      CDLLADDERBOTTOM(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLLONGLEGGEDDOJI Long Legged Doji (K线图:长腿十字线)
      CDLLONGLEGGEDDOJI(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLLONGLINE Long Line Candle (K线图:长线)
      CDLLONGLINE(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLMARUBOZU Marubozu (K线图:光头光脚 )
      CDLMARUBOZU(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLMATCHINGLOW Matching Low (K线图:匹配低)
      CDLMATCHINGLOW(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLMATHOLD Mat Hold (K线图:垫住)
      CDLMATHOLD(Records[Open,High,Low,Close],Penetration = 0.5) = Array(outInteger)
      CDLMORNINGDOJISTAR Morning Doji Star (K线图:早晨十字星)
      CDLMORNINGDOJISTAR(Records[Open,High,Low,Close],Penetration = 0.3) = Array(outInteger)
      CDLMORNINGSTAR Morning Star (K线图:晨星)
      CDLMORNINGSTAR(Records[Open,High,Low,Close],Penetration = 0.3) = Array(outInteger)
      CDLONNECK On-Neck Pattern (K线图:颈型)
      CDLONNECK(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLPIERCING Piercing Pattern (K线图:穿孔模式)
      CDLPIERCING(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLRICKSHAWMAN Rickshaw Man (K线图:车夫)
      CDLRICKSHAWMAN(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLRISEFALL3METHODS Rising/Falling Three Methods (K线图:上升/下降三法)
      CDLRISEFALL3METHODS(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLSEPARATINGLINES Separating Lines (K线图:分割线)
      CDLSEPARATINGLINES(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLSHOOTINGSTAR Shooting Star (K线图:流星)
      CDLSHOOTINGSTAR(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLSHORTLINE Short Line Candle (K线图:短线)
      CDLSHORTLINE(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLSPINNINGTOP Spinning Top (K线图:陀螺)
      CDLSPINNINGTOP(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLSTALLEDPATTERN Stalled Pattern (K线图:停滞模式)
      CDLSTALLEDPATTERN(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLSTICKSANDWICH Stick Sandwich (K线图:棍子三明治)
      CDLSTICKSANDWICH(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLTAKURI Takuri (Dragonfly Doji with very long lower shadow) (K线图:托里)
      CDLTAKURI(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLTASUKIGAP Tasuki Gap (K线图:翼隙)
      CDLTASUKIGAP(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLTHRUSTING Thrusting Pattern (K线图:推模式)
      CDLTHRUSTING(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLTRISTAR Tristar Pattern (K线图:三星模式)
      CDLTRISTAR(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLUNIQUE3RIVER Unique 3 River (K线图:独特的3河)
      CDLUNIQUE3RIVER(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLUPSIDEGAP2CROWS Upside Gap Two Crows (K线图:双飞乌鸦)
      CDLUPSIDEGAP2CROWS(Records[Open,High,Low,Close]) = Array(outInteger)
      CDLXSIDEGAP3METHODS Upside/Downside Gap Three Methods (K线图:上行/下行缺口三方法)
      CDLXSIDEGAP3METHODS(Records[Open,High,Low,Close]) = Array(outInteger)

      Volume Indicators 量指标

      指标 描述
      AD Chaikin A/D Line (线随机指标)
      AD(Records[High,Low,Close,Volume]) = Array(outReal)
      ADOSC Chaikin A/D Oscillator (佳庆指标)
      ADOSC(Records[High,Low,Close,Volume],Fast Period = 3,Slow Period = 10) = Array(outReal)
      OBV On Balance Volume (能量潮)
      OBV(Records[Close],Records[Volume]) = Array(outReal)

      Math Transform 数学变换

      指标 描述
      ACOS Vector Trigonometric ACos (反余弦函数)
      ACOS(Records[Close]) = Array(outReal)
      ASIN Vector Trigonometric ASin (反正弦函数)
      ASIN(Records[Close]) = Array(outReal)
      ATAN Vector Trigonometric ATan (反正切函数)
      ATAN(Records[Close]) = Array(outReal)
      CEIL Vector Ceil (取整函数)
      CEIL(Records[Close]) = Array(outReal)
      COS Vector Trigonometric Cos (余弦函数)
      COS(Records[Close]) = Array(outReal)
      COSH Vector Trigonometric Cosh (双曲余弦值)
      COSH(Records[Close]) = Array(outReal)
      EXP Vector Arithmetic Exp (指数函数)
      EXP(Records[Close]) = Array(outReal)
      FLOOR Vector Floor (向下取整)
      FLOOR(Records[Close]) = Array(outReal)
      LN Vector Log Natural (自然对数)
      LN(Records[Close]) = Array(outReal)
      LOG10 Vector Log10 (对数函数)
      LOG10(Records[Close]) = Array(outReal)
      SIN Vector Trigonometric Sin (正弦值)
      SIN(Records[Close]) = Array(outReal)
      SINH Vector Trigonometric Sinh (双曲正弦函数)
      SINH(Records[Close]) = Array(outReal)
      SQRT Vector Square Root (平方根)
      SQRT(Records[Close]) = Array(outReal)
      TAN Vector Trigonometric Tan (正切)
      TAN(Records[Close]) = Array(outReal)
      TANH Vector Trigonometric Tanh (双曲正切函数)
      TANH(Records[Close]) = Array(outReal)

      Math Operators 数学运算符

      指标 描述
      MAX Highest value over a specified period (最大值)
      MAX(Records[Close],Time Period = 30) = Array(outReal)
      MAXINDEX Index of highest value over a specified period (最大值索引)
      MAXINDEX(Records[Close],Time Period = 30) = Array(outInteger)
      MIN Lowest value over a specified period (最小值)
      MIN(Records[Close],Time Period = 30) = Array(outReal)
      MININDEX Index of lowest value over a specified period (最小值索引)
      MININDEX(Records[Close],Time Period = 30) = Array(outInteger)
      MINMAX Lowest and highest values over a specified period (最小最大值)
      MINMAX(Records[Close],Time Period = 30) = [Array(outMin),Array(outMax)]
      MINMAXINDEX Indexes of lowest and highest values over a specified period (最小最大值索引)
      MINMAXINDEX(Records[Close],Time Period = 30) = [Array(outMinIdx),Array(outMaxIdx)]
      SUM Summation (求和)
      SUM(Records[Close],Time Period = 30) = Array(outReal)

      Cycle Indicators 循环指标

      指标 描述
      HT_DCPERIOD Hilbert Transform - Dominant Cycle Period (希尔伯特变换, 主周期)
      HT_DCPERIOD(Records[Close]) = Array(outReal)
      HT_DCPHASE Hilbert Transform - Dominant Cycle Phase (希尔伯特变换,主阶段)
      HT_DCPHASE(Records[Close]) = Array(outReal)
      HT_PHASOR Hilbert Transform - Phasor Components (希尔伯特变换,相成分)
      HT_PHASOR(Records[Close]) = [Array(outInPhase),Array(outQuadrature)]
      HT_SINE Hilbert Transform - SineWave (希尔伯特变换,正弦波)
      HT_SINE(Records[Close]) = [Array(outSine),Array(outLeadSine)]
      HT_TRENDMODE Hilbert Transform - Trend vs Cycle Mode (希尔伯特变换-趋势与周期模式)
      HT_TRENDMODE(Records[Close]) = Array(outInteger)

      Volatility Indicators 波动性指标

      指标 描述
      ATR Average True Range (平均真实波幅)
      ATR(Records[High,Low,Close],Time Period = 14) = Array(outReal)
      NATR Normalized Average True Range (归一化平均值范围)
      NATR(Records[High,Low,Close],Time Period = 14) = Array(outReal)
      TRANGE True Range (真实范围)
      TRANGE(Records[High,Low,Close]) = Array(outReal)

      Overlap Studies 重叠的研究

      指标 描述
      BBANDS Bollinger Bands (布林带)
      BBANDS(Records[Close],Time Period = 5,Deviations up = 2,Deviations down = 2,MA Type = 0) = [Array(outRealUpperBand),Array(outRealMiddleBand),Array(outRealLowerBand)]
      DEMA Double Exponential Moving Average (双指数移动平均线)
      DEMA(Records[Close],Time Period = 30) = Array(outReal)
      EMA Exponential Moving Average (指数移动平均线)
      EMA(Records[Close],Time Period = 30) = Array(outReal)
      HT_TRENDLINE Hilbert Transform - Instantaneous Trendline (希尔伯特变换,瞬时趋势)
      HT_TRENDLINE(Records[Close]) = Array(outReal)
      KAMA Kaufman Adaptive Moving Average (适应性移动平均线)
      KAMA(Records[Close],Time Period = 30) = Array(outReal)
      MA Moving average (移动平均线)
      MA(Records[Close],Time Period = 30,MA Type = 0) = Array(outReal)
      MAMA MESA Adaptive Moving Average (MESA 移动平均线)
      MAMA(Records[Close],Fast Limit = 0.5,Slow Limit = 0.05) = [Array(outMAMA),Array(outFAMA)]
      MIDPOINT MidPoint over period (中点)
      MIDPOINT(Records[Close],Time Period = 14) = Array(outReal)
      MIDPRICE Midpoint Price over period (中点价格)
      MIDPRICE(Records[High,Low],Time Period = 14) = Array(outReal)
      SAR Parabolic SAR (抛物线转向)
      SAR(Records[High,Low],Acceleration Factor = 0.02,AF Maximum = 0.2) = Array(outReal)
      SAREXT Parabolic SAR - Extended (增强型抛物线转向)
      SAREXT(Records[High,Low],Start Value = 0,Offset on Reverse = 0,AF Init Long = 0.02,AF Long = 0.02,AF Max Long = 0.2,AF Init Short = 0.02,AF Short = 0.02,AF Max Short = 0.2) = Array(outReal)
      SMA Simple Moving Average (简单移动平均)
      SMA(Records[Close],Time Period = 30) = Array(outReal)
      T3 Triple Exponential Moving Average (T3) (三指数移动平均)
      T3(Records[Close],Time Period = 5,Volume Factor = 0.7) = Array(outReal)
      TEMA Triple Exponential Moving Average (三指数移动平均)
      TEMA(Records[Close],Time Period = 30) = Array(outReal)
      TRIMA Triangular Moving Average (三指数移动平均)
      TRIMA(Records[Close],Time Period = 30) = Array(outReal)
      WMA Weighted Moving Average (加权移动平均)
      WMA(Records[Close],Time Period = 30) = Array(outReal)

      Statistic Functions 统计功能

      指标 描述
      LINEARREG Linear Regression (线性回归)
      LINEARREG(Records[Close],Time Period = 14) = Array(outReal)
      LINEARREG_ANGLE Linear Regression Angle (线性回归的角度)
      LINEARREG_ANGLE(Records[Close],Time Period = 14) = Array(outReal)
      LINEARREG_INTERCEPT Linear Regression Intercept (线性回归截距)
      LINEARREG_INTERCEPT(Records[Close],Time Period = 14) = Array(outReal)
      LINEARREG_SLOPE Linear Regression Slope (线性回归斜率)
      LINEARREG_SLOPE(Records[Close],Time Period = 14) = Array(outReal)
      STDDEV Standard Deviation (标准偏差)
      STDDEV(Records[Close],Time Period = 5,Deviations = 1) = Array(outReal)
      TSF Time Series Forecast (时间序列预测)
      TSF(Records[Close],Time Period = 14) = Array(outReal)
      VAR Variance (方差)
      VAR(Records[Close],Time Period = 5,Deviations = 1) = Array(outReal)

      Momentum Indicators 动量指标

      指标 描述
      ADX Average Directional Movement Index (平均趋向指数)
      ADX(Records[High,Low,Close],Time Period = 14) = Array(outReal)
      ADXR Average Directional Movement Index Rating (评估指数)
      ADXR(Records[High,Low,Close],Time Period = 14) = Array(outReal)
      APO Absolute Price Oscillator (绝对价格振荡指数)
      APO(Records[Close],Fast Period = 12,Slow Period = 26,MA Type = 0) = Array(outReal)
      AROON Aroon (阿隆指标)
      AROON(Records[High,Low],Time Period = 14) = [Array(outAroonDown),Array(outAroonUp)]
      AROONOSC Aroon Oscillator (阿隆震荡线)
      AROONOSC(Records[High,Low],Time Period = 14) = Array(outReal)
      BOP Balance Of Power (均势指标)
      BOP(Records[Open,High,Low,Close]) = Array(outReal)
      CCI Commodity Channel Index (顺势指标)
      CCI(Records[High,Low,Close],Time Period = 14) = Array(outReal)
      CMO Chande Momentum Oscillator (钱德动量摆动指标)
      CMO(Records[Close],Time Period = 14) = Array(outReal)
      DX Directional Movement Index (动向指数)
      DX(Records[High,Low,Close],Time Period = 14) = Array(outReal)
      MACD Moving Average Convergence/Divergence (指数平滑移动平均线)
      MACD(Records[Close],Fast Period = 12,Slow Period = 26,Signal Period = 9) = [Array(outMACD),Array(outMACDSignal),Array(outMACDHist)]
      MACDEXT MACD with controllable MA type (MA型可控 MACD)
      MACDEXT(Records[Close],Fast Period = 12,Fast MA = 0,Slow Period = 26,Slow MA = 0,Signal Period = 9,Signal MA = 0) = [Array(outMACD),Array(outMACDSignal),Array(outMACDHist)]
      MACDFIX Moving Average Convergence/Divergence Fix 12/26 (移动平均收敛/发散修复12/26)
      MACDFIX(Records[Close],Signal Period = 9) = [Array(outMACD),Array(outMACDSignal),Array(outMACDHist)]
      MFI Money Flow Index (货币流量指数)
      MFI(Records[High,Low,Close,Volume],Time Period = 14) = Array(outReal)
      MINUS_DI Minus Directional Indicator (负向指标)
      MINUS_DI(Records[High,Low,Close],Time Period = 14) = Array(outReal)
      MINUS_DM Minus Directional Movement (负向运动)
      MINUS_DM(Records[High,Low],Time Period = 14) = Array(outReal)
      MOM Momentum (动量)
      MOM(Records[Close],Time Period = 10) = Array(outReal)
      PLUS_DI Plus Directional Indicator (更向指示器)
      PLUS_DI(Records[High,Low,Close],Time Period = 14) = Array(outReal)
      PLUS_DM Plus Directional Movement (定向运动)
      PLUS_DM(Records[High,Low],Time Period = 14) = Array(outReal)
      PPO Percentage Price Oscillator (价格振荡百分比)
      PPO(Records[Close],Fast Period = 12,Slow Period = 26,MA Type = 0) = Array(outReal)
      ROC Rate of change : ((price/prevPrice)-1)*100 (变动率指标)
      ROC(Records[Close],Time Period = 10) = Array(outReal)
      ROCP Rate of change Percentage: (price-prevPrice)/prevPrice (价格变化率)
      ROCP(Records[Close],Time Period = 10) = Array(outReal)
      ROCR Rate of change ratio: (price/prevPrice) (价格变化率)
      ROCR(Records[Close],Time Period = 10) = Array(outReal)
      ROCR100 Rate of change ratio 100 scale: (price/prevPrice)*100 (价格变化率)
      ROCR100(Records[Close],Time Period = 10) = Array(outReal)
      RSI Relative Strength Index (相对强弱指标)
      RSI(Records[Close],Time Period = 14) = Array(outReal)
      STOCH Stochastic (STOCH指标)
      STOCH(Records[High,Low,Close],Fast-K Period = 5,Slow-K Period = 3,Slow-K MA = 0,Slow-D Period = 3,Slow-D MA = 0) = [Array(outSlowK),Array(outSlowD)]
      STOCHF Stochastic Fast (快速STOCH指标)
      STOCHF(Records[High,Low,Close],Fast-K Period = 5,Fast-D Period = 3,Fast-D MA = 0) = [Array(outFastK),Array(outFastD)]
      STOCHRSI Stochastic Relative Strength Index (随机强弱指数)
      STOCHRSI(Records[Close],Time Period = 14,Fast-K Period = 5,Fast-D Period = 3,Fast-D MA = 0) = [Array(outFastK),Array(outFastD)]
      TRIX 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA (三重指数平滑平均线)
      TRIX(Records[Close],Time Period = 30) = Array(outReal)
      ULTOSC Ultimate Oscillator (极限振子)
      ULTOSC(Records[High,Low,Close],First Period = 7,Second Period = 14,Third Period = 28) = Array(outReal)
      WILLR Williams’ %R (威廉指标)
      WILLR(Records[High,Low,Close],Time Period = 14) = Array(outReal)

      Price Transform 价格指标

      指标 描述
      AVGPRICE Average Price (平均价格)
      AVGPRICE(Records[Open,High,Low,Close]) = Array(outReal)
      MEDPRICE Median Price (中位数价格)
      MEDPRICE(Records[High,Low]) = Array(outReal)
      TYPPRICE Typical Price (典型价格)
      TYPPRICE(Records[High,Low,Close]) = Array(outReal)
      WCLPRICE Weighted Close Price (加权收盘价)
      WCLPRICE(Records[High,Low,Close]) = Array(outReal)
  • 4. FMZ 平台扩展API

    为了更方便的满足用户各种环境下操作机器人的需要求,FMZ推出平台API调用功能

    • 1、创建ApiKey

      img

    • 2、API返回码(code)

      描述 代码
      执行成功 0
      错误的ApiKey 1
      错误的签名 2
      Nonce错误 3
      方法不正确 4
      参数不正确 5
      内部未知错误 6
    • 3、机器人状态

      (正常启动)

      状态 代码
      空闲中 0
      运行中 1
      停止中 2
      已退出 3
      被停止 4
      策略有错误 5

      (异常)

      状态 代码
      策略已过期, 请联系作者重新购买 -1
      没有找到托管者 -2
      策略编译错误 -3
      机器人已经是运行状态 -4
      余额不足 -5
      策略并发数超限 -6
    • 4、简单的例子

      python 语言、支持 python2 、python3

      #!/usr/bin/python
      # -*- coding: utf-8 -*-
      import time
      import json
      import ssl
      ssl._create_default_https_context = ssl._create_unverified_context
      
      try:
          import md5
          import urllib2
          from urllib import urlencode
      except:
          import hashlib as md5
          import urllib.request as urllib2
          from urllib.parse import urlencode
      
      accessKey = 'f27bfcXXXXXXXX013c62e98XXXXX817a'
      secretKey = 'ffeXXXXXXXX085ff7269XXXXXXXX6f82'
      
      def api(method, *args):
          d = {
              'version': '1.0',
              'access_key': accessKey,
              'method': method,
              'args': json.dumps(list(args)),
              'nonce': int(time.time() * 1000),
              }
      
          d['sign'] = md5.md5(('%s|%s|%s|%d|%s' % (d['version'], d['method'], d['args'], d['nonce'], secretKey)).encode('utf-8')).hexdigest()
          return json.loads(urllib2.urlopen('https://www.fmz.com/api/v1', urlencode(d).encode('utf-8')).read().decode('utf-8'))
          # 注意: urllib2.urlopen 函数,超时问题,可以设置超时时间。
          # urllib2.urlopen('https://www.fmz.com/api/v1', urlencode(d).encode('utf-8'), timeout=10) # 设置超时 10秒。
      
      print(api('GetNodeList'))              # 返回托管者列表
      print(api('GetPlatformList'))          # 返回交易所列表
      print(api('GetRobotList', -1, -1, -1)) # GetRobotList(offset, length, robotStatus int) 传-1代表获取全部
      print(api('CommandRobot', 123, 'ok'))  # CommandRobot(robotId int64, cmd string) 向机器人发送命令
      print(api('StopRobot', 123))           # StopRobot(robotId int64) 返回机器人状态代码
      print(api('RestartRobot', 123))        # RestartRobot(robotId int64) 返回机器人状态代码
      print(api('GetRobotDetail', 123))      # GetRobotDetail(robotId int64) 返回机器人详细信息
      

      Golang

      package main
      
      import (
          "fmt"
          "time"
          "encoding/json"
          "crypto/md5"
          "encoding/hex"
          "net/http"
          "io/ioutil"
          "strconv"
          "net/url"
      )
      
      var apiKey string = ""                                  // 填写自己的 FMZ 平台 api key
      var secretKey string = ""                               // 填写自己的 FMZ 平台 secret key
      var baseApi string = "https://www.fmz.com/api/v1"
      
      func api(method string, args ... interface{}) (ret interface{}) {
          // 处理 args 
          jsonStr, err := json.Marshal(args)
          if err != nil {
              panic(err)
          }
      
          var params map[string]string = map[string]string{
              "version" : "1.0", 
              "access_key" : apiKey,
              "method" : method,
              "args" : string(jsonStr),
              "nonce" : strconv.FormatInt(time.Now().UnixNano() / 1e6, 10),
          }    
      
          data := fmt.Sprintf("%s|%s|%s|%v|%s", params["version"], params["method"], params["args"], params["nonce"], secretKey)
          h := md5.New()
          h.Write([]byte(data))
          sign := h.Sum(nil)
      
          params["sign"] = hex.EncodeToString(sign)
      
          // http request 
          client := &http.Client{}
      
          // request 
          urlValue := url.Values{}
          for k, v := range params {
              urlValue.Add(k, v)
          }
          urlStr := urlValue.Encode()
          request, err := http.NewRequest("GET", baseApi + "?" + urlStr, nil)
          if err != nil {
              panic(err)
          }    
      
          resp, err := client.Do(request)
          if err != nil {
              panic(err)
          }
      
          defer resp.Body.Close()
      
          b, err := ioutil.ReadAll(resp.Body)
          if err != nil {
              panic(err)
          }
      
          ret = string(b)
      
          return 
      }
      
      func main() {
          settings := map[string]interface{}{
              "name": "hedge test",
              "strategy": 104150,                      
              "period": 60,                           
              "node" : 73938,                         
              "appid": "member2",                
              "exchanges": []interface{}{
                  map[string]interface{}{
                      "eid": "Exchange", 
                      "label" : "test_bjex", 
                      "pair": "BTC_USDT", 
                      "meta" : map[string]interface{}{
                          "AccessKey": "",                                // 填写 access key
                          "SecretKey": "",                                // 填写 secret key
                          "Front" : "http://127.0.0.1:6666/exchange",
                      },
                  },
              },
          }
      
          method := "RestartRobot"
          fmt.Println("调用接口:", method)
          ret := api(method, 124577, settings)
          fmt.Println("main ret:", ret)
      }
      
    • 5、扩展 API 详解

      • FMZ API 接口、参数。

        https://www.fmz.com/api/v1?

        以上其中 ? 符号后跟 请求参数。

        python 语言描述 请求参数:

        {
            'version'   : '1.0',
            'access_key': '8a1f6c3785fd78a1848320e0b19js99f',   # access key , 在账户管理页面申请
            'method'    : 'GetNodeList',                        # 具体调用的 方法
            'args'      : [],                                   # 具体 method 算法的参数列表。
            'nonce'     : 1516292399361,                        # 时间戳,单位毫秒,允许 和 标准时间 时间戳前后误差1小时。
                                                                # nonce 必须比 上一次 访问时的 nonce 数值大。
            'sign'      : '085b63456c93hfb243a757366600f9c2'    # 签名
        }
        

        参数以 字符 & 分隔 参数名和参数值用符号 = 连接 完整的请求URL (method=GetNodeList 为例):

        https://www.fmz.com/api/v1?
        access_key=8a1f6c3785fd78a1848320e0b19js99f&
        nonce=1516292399361&
        args=%5B%5D&
        sign=085b63456c93hfb243a757366600f9c2&
        version=1.0&
        method=GetNodeList
        # 注意请求参数中 没有 secret key
        
      • 签名方式

        请求参数中,sign 参数是一个加密字符串,加密方法如下: 按照格式:

        version + "|" + method + "|" + args + "|" + nonce + "|" + secretKey
        

        拼接字符串后 使用 MD5 加密算法加密字符串,并转换为十六进制数据字符串值 该值作为参数sign的值。

        参考代码(python为例)

        # 参数
        d = {
            'version': '1.0',
            'access_key': accessKey,
            'method': method,
            'args': json.dumps(list(args)),
            'nonce': int(time.time() * 1000),
        }
        
        # 计算 sign 签名(加密)
        d['sign'] = md5.md5(('%s|%s|%s|%d|%s' % (d['version'], d['method'], d['args'], d['nonce'], secretKey)).encode('utf-8')).hexdigest()
        
      • 1、method : ‘GetNodeList’ 返回托管者列表

        参数 args

        返回值

        {
            "code": 0,
            "data": {
                "result": {
                    "nodes": [{
                        "build": "3.3",                 # 版本号
                        "date": "2018-01-19 10:35:24",
                        "id": 34500,
                        "ip": "126.28.21.120",
                        "loaded": 1,                    # 该托管者上 运行的机器人数量
                        "name": "iZ9116xhkgtZ",
                        "online": true,                 # 是否在线
                        "os": "linux",                  # 操作系统 
                        "wd": 0                         # 是否开启 离线报警
                    },
                    ...
                    ]
                },
                "error": null
            }
        }
        
      • 2、method : ‘GetPlatformList’ 返回已添加的交易所列表

        参数 args

        返回值

        {
            "code": 0,
            "data": {
                "result": {
                    "platforms": [{
                        "eid": "Huobi",
                        "id": 12483,
                        "label": "火币 - 测试ETH/ETC",                            # 添加交易所时的标签
                        "logo": "huobi.png",
                        "name": "火币",
                        "stocks": ["LTC_BTC", "ETH_BTC", "ETC_BTC", "BCH_BTC"],
                        "website": "https://www.huobi.pro/"
                    }, {
                        "eid": "AEX",
                        "id": 16345,
                        "label": "AEX",
                        "logo": "",
                        "name": "AEX",
                        "stocks": ["LTC_BTC", "ETH_BTC", "ETC_BTC", "BCC_BTC"],
                        "website": "https://www.aex.com/"
                    },
                    ...
                    ]
                },
                "error": null
            }
        }
        
      • 3、method : ‘GetRobotList’ 返回机器人列表

        参数 args

        offset 为int类型, length 为int类型, robotStatus 为int类型, label 为string类型。 
        
        # offset
        # length
        # robotStatus    传-1代表获取全部
        # label          自定义标签, 可以筛选出 这个标签的所有 机器人。
        
        # 范例 python 代码 ,参看以上 " 4、简单的例子 " ,以下是python 调用范例:
        print api('GetRobotList', 'member2')           # 把自定义标签为member2的机器人全列出来
        print api('GetRobotList', 0, 5, -1, 'member2') # 分页从0到5列出来最多5个标签为member2的机器人
        

        返回值

        {
            "code": 0,
            "data": {
                "result": {
                    "all": 53,
                    "robots": [{
                        "date": "2017-12-25 09:29:27",
                        "end_time": "2017-12-28 17:44:21",
                        "id": 66054,
                        "is_sandbox": 1,                                      # 值为 1 则该机器人为模拟盘机器人。 
                        "name": "C++ 测试策略",
                        "node_guid": "705d9aaaaaaaa93b49baaaaa787581cb087",
                        "profit": 0,
                        "public": 0,
                        "refresh": 151345645647000,
                        "start_time": "2017-12-28 17:44:15",
                        "status": 3,
                        "strategy_id": 65365,
                        "strategy_isowner": true,
                        "strategy_name": "C++  版本  托管者  API  测试策略(数字货币期货、现货市场)",
                        "wd": 0
                    }, {
                        "date": "2016-11-25 18:41:03",
                        "end_time": "2017-12-25 14:28:01",
                        "id": 43568,
                        "is_sandbox": 1,
                        "name": "测试东航实盘",
                        "node_guid": "fcd03b2ffffffff12ggggb1e706e",
                        "profit": 0,
                        "public": 0,
                        "refresh": 1514625678000,
                        "start_time": "2017-12-25 14:27:26",
                        "status": 4,
                        "strategy_id": 24738,
                        "strategy_isowner": true,
                        "strategy_name": "测试-CTP商品期货连接状态 (图表显示)",
                        "wd": 0
                    },
                    ...
                    ]
                },
                "error": null
            }
        }
        
      • 4、method : ‘CommandRobot’ 向指定ID的机器人发送命令(由 策略 中调用的 GetCommand API 捕获)

        参数 args

        robotId 为int类型, cmd 为string类型 ,向机器人发送命令。
        
        # robotId : 机器人ID , 可以用   GetRobotList 获取
        # cmd     : 该参数是 发送给机器人的 指令, 在机器人策略中 的 GetCommand 函数 会捕获到该命令,
        #           触发交互(由策略具体实现)。
        

        返回值

        {
            "code": 0,                 # 该次 API 请求 执行成功。
            "data": {
                "result": false,       # 但是,向一个 没有运行的机器人发送 指令, 返回失败。
                "error": null
            }
        }
        
      • 5、method : ‘StopRobot’ 停止指定ID的机器人

        参数 args

        robotId 为int类型。       # 返回机器人状态代码
        
        # robotId  : 机器人  ID  可以用   GetRobotList 获取
        

        返回值

        {
            "code": 0,
            "data": {
                "result": 2,           # 2 即 停止中
                "error": null
            }
        }
        
      • 6、method : ‘RestartRobot’ 重启指定ID的机器人

        参数 args

        # 1、不配置 机器人、策略 参数
        robotId 为int类型                         # 返回机器人状态代码
        # robotId  : 机器人 ID 可以用   GetRobotList 获取
        
        # 2、配置 机器人、策略 参数
        robotId 为int类型, settings 为Object类型   # 返回机器人状态代码
        # robotId  : 机器人 ID 可以用   GetRobotList 获取
        # settings : 配置数据对象, 和 创建机器人使用的 settings 参数 格式一致,如下:
          settings = {
              "name": "hedge test",
              "args": [["Interval", 500]],            # 策略参数
              "strategy": 25189,                      # 策略ID , 可以用 GetStrategyList 方法获取到,
              "period": 60,                           # 周期分钟数
              "node" : 51924,                         # 指定在哪个托管者上运行,不写该属性就是自动分配运行。
              "appid": "member2",                     # 自定义字段
              "exchanges": [
                  {"pid": 15445, "pair": "ETH_BTC"},     # ZB  , pid 可以由 GetExchangeList 方法获取到,
                  {"pid": 13802, "pair": "BCH_BTC"},     # OKEX , 配置了2个 交易所对象。
                  
              # 除了FMZ控制中心配置好的交易所(pid 识别),还可以设置 没有配置过的交易所 配置信息,用来给机器人操作。
                  {"eid": "OKEX", "pair": "ETH_BTC", "meta" :{"AccessKey": "xxx", "SecretKey": "yyy"}},
                  {"eid": "Huobi", "pair": "BCH_BTC", "meta" :{"AccessKey": "xxx", "SecretKey": "yyy"}},
              # 注意:
              # eid 识别的 配置中 , "meta" :{"AccessKey": "xxx", "SecretKey": "yyy"} 这些敏感 信息 (API 密钥)
              # FMZ 是不储存的,直接转发给 托管者程序 ,所以每次创建 或者 重启 机器人时,必须 配置该 信息。
              ],
          }
        

        如何重启使用插件支持交易所的机器人: 在配置settings这个参数时,对于 exchanges 属性,可以使用 如下 设置:

        {"eid": "Exchange", "label" : "testOCX", "pair": "ETH_BTC", "meta" :{"AccessKey": "123", "SecretKey": "1234", "Front" : "http://127.0.0.1:6666/OCX"}},
        

        “label” 属性是给当前通用协议接入的交易所对象设置一个标签,在策略中可以使用 GetLabel 函数获取。

        返回值

        {
            "code": 0,
            "data": {
                "result": 1,          # 1 即 运行中
                "error": null
            }
        }
        
      • 7、method : ‘GetRobotDetail’ 获取指定ID的机器人详细信息

        参数 args

        robotId 为int类型     #  返回机器人详细信息
        # robotId  : 机器人 ID 可以用   GetRobotList 获取
        

        返回值

        {
            "code": 0,
            "data": {
                "result": {
                    "robot": {
                        "date": "2016-12-01 12:19:01",
                        "debug": "{"Nano":1516333784449179603,"Stderr":"","Stdout":""}",
                        "end_time": "2018-01-19 11:49:44",
                        "fixed_id": 41145,
                        "id": 43800,
                        "is_manager": true,
                        "is_sandbox": 0,
                        "name": "测试连接宏源期货主席",
                        "node_id": 41145,
                        "pexchanges": {
                            "8506": "Futures_CTP"
                        },
                        "plabels": {
                            "8506": "宏源期货主席"
                        },
                        "profit": 0,
                        "public": 0,
                        "refresh": 1516333783000,
                        "robot_args": "[["testContractType","jm1801"],["indicatorsName","指标轴1",20967],["indicators_1","指标1",20967],["indicators_2","指标2",20967],["Interval",500,20967],["isOpenRightY",true,20967],["lineType","line",20967]]",
                        "start_time": "2018-01-19 11:47:18",
                        "status": 4,
                        "strategy_args": "[["testContractType","测试的合约类型","合约代码","MA701"]]",
                        "strategy_exchange_pairs": "[0,[8506],["FUTURES"]]",
                        "strategy_id": 22838,
                        "strategy_last_modified": "2017-02-28 13:55:41",
                        "strategy_name": "测试-CTP商品期货连接状态 (图表显示)",
                        "summary": "当前时间:2018-01-19 11:49:41.996+08:00msg:time:2018-01-19 11:49:41.996+08:00n`{"type":"table","title":"运行信息","cols":["实时状态:exchange.IO('status') ↓","test ContractType ↓","infomation ↓"],"rows":[[true,"jm1801",""],["","ticker ↓#FF0000","Account ↓#FF0000"],["",null,{"Info":{"PreMargin":0,"SpecProductPositionProfit":0,"SpecProductPositionProfitByAlg":0,"AccountID":"900352098","PreMortgage":0,"PreDeposit":0,"ExchangeMargin":0,"ExchangeDeliveryMargin":0,"FundMortgageOut":0,"FundMortgageAvailable":0,"PreCredit":0,"Interest":0,"FrozenMargin":0,"CloseProfit":0,"PositionProfit":0,"Reserve":0,"TradingDay":"20180119","MortgageableFund":0,"SpecProductFrozenCommission":0,"PreFundMortgageOut":0,"SpecProductFrozenMargin":0,"SpecProductCloseProfit":0,"Available":0,"InterestBase":0,"Withdraw":0,"FrozenCash":0,"FrozenCommission":0,"CurrMargin":0,"Commission":0,"Balance":0,"Credit":0,"Mortgage":0,"FundMortgageIn":0,"SpecProductMargin":0,"BrokerID":"1080","SpecProductCommission":0,"PreBalance":0,"Deposit":0,"CashIn":0,"CurrencyID":"CNY","SpecProductExchangeMargin":0,"WithdrawQuota":0,"SettlementID":1,"DeliveryMargin":0,"ReserveBalance":0,"PreFundMortgageIn":0},"Balance":0,"FrozenBalance":0}],["","records[-1] ↓#FF0000",""],["","null",""]]}`",
                        "templates": [{
                            "args": "[["indicatorsName","指标轴","字符","指标轴1"],["indicators_1","指标1","字符","指标1"],["indicators_2","指标2","字符","指标2"],["Interval","间隔(毫秒)","数值",500],["isOpenRightY","是否开启右边Y轴","默认是开启右边单独的Y轴用于指标数值",true],["lineType","指标线类型","line、spline","line"]]",
                            "category": 20,
                            "id": 20967,
                            "name": "图表模板(增加状态栏表格)"
                        }],
                        "wd": 0
                    }
                },
                "error": null
            }
        }
        
      • 8、method : ‘GetAccount’ 返回用户信息

        参数 args

        返回值

        {
            "code": 0, 
            "data": {
                "result": {
                    "username": "littlelittledream",
                    "level": 0,
                    "consumed": 3235500000,
                    "invitation_code": "1545967",
                    "points": 25,
                    "balance": 6542100000               # 此处的数值 是由于精度控制,使用的是整数表示,换算成实际数值 需要 除以 1e8  (即:10 的 8 次方),实际此处得出 :65.421 。
                },
                "error": None
            }
        }
        
      • 9、method : ‘GetExchangeList’ 返回支持的交易所列表以及需要的配置信息

        参数 args

        返回值

        {
            "code": 0,
            "data": {
                "result": {
                    "exchanges": [{
                        "website": "https://www.huobi.pro/",
                        "name": "火币",
                        "priority": 1,
                        "meta": "[{"desc": "Access Key", "required": true, "type": "string", "name": "AccessKey", "label": "Access Key"}, {"encrypt": true, "name": "SecretKey", "required": true, "label": "Secret Key", "type": "password", "desc": "Secret Key"}]",
                        "eid": "Huobi",
                        "logo": "huobi.png",
                        "id": 1
                    }, {
                        "website": "https://www.kex.com/",
                        "name": "KEX",
                        "priority": -99,
                        "meta": "[{"desc": "Access Key", "required": true, "type": "string", "name": "AccessKey", "label": "Access Key"}, {"encrypt": true, "name": "SecretKey", "required": true, "label": "Secret Key", "type": "password", "desc": "Secret Key"}, {"encrypt": true, "required": true, "type": "password", "name": "Password", "label": "交易密码"}]",
                        "eid": "KEX",
                        "logo": "",
                        "id": 43
                    }, 
        
                    ...
              
                    ]
                },
                "error": null
            }
        }
        
      • 10、method : ‘DeleteRobot’

        参数 args

        robotId 为int类型
        # robotId 要删除的机器人的 ID 
        
        deleteLogs 为布尔类型
        # deleteLogs 设置是否要删除日志,如果传入 true, 即删除日志。
        

        返回值

        # 机器人删除 成功 返回值
        {
            "code": 0,
            "data": {
                "result": 0,
                "error": null
            }
        }
        
      • 11、method : ‘GetStrategyList’ 获取策略列表

        参数 args

        返回值

        {
            "code": 0,
            "data": {
                "result": {
                    "strategies": [{
                        "category": 0,
                        "username": "yifidslei",
                        "is_owner": true,
                        "name": "fmz 模拟盘测试策略",
                        "language": 0,
                        "hasToken": false,
                        "args": "[]",
                        "is_buy": false,
                        "public": 0,
                        "last_modified": "2018-01-18 12:36:03",
                        "date": "2018-01-17 09:19:32",
                        "forked": 0,
                        "id": 63372
                    }, {
                        "category": 20,
                        "username": "bifndslez",
                        "is_owner": true,
                        "name": "画线类库",
                        "language": 0,
                        "hasToken": false,
                        "args": "[]",
                        "is_buy": false,
                        "public": 0,
                        "last_modified": "2017-05-08 09:44:18",
                        "date": "2017-04-19 10:38:14",
                        "forked": 0,
                        "id": 39677
                    },
                    
                    ...
                    ],
                    "all": 20
                },
                "error": null
            }
        }
        
      • 12、method : ‘NewRobot’ 根据 参数设置 创建一个新的机器人。

        参数 args

        settings 为Object类型
        # settings 是一个 机器人 配置 对象,描述解释如下:
        

        settings 对象各属性描述:

        settings = {
            "name": "hedge test",
            "args": [["Interval", 500], ["MAType", 0, 75882]],            # 策略参数, 不一定要 和 策略参数顺序一致,不过 参数名必须 一致。
                                                                          # 注意:参数数组中第二个元素["MAType", 0, 75882] 是一个 包含三个元素的数组, 
                                                                          # 其中第一个元素 MAType 是该机器人绑定策略引用的模板上的参数,
                                                                          # 第二个元素 0 是 参数 MAType 的设置的具体值,
                                                                          # 第三个元素 75882 是 MAType 这个参数所属模板的 ID,用来 标识确定 这个参数 是哪个模板的参数。
            "strategy": 25189,                      # 策略ID , 可以用 GetStrategyList 方法获取到,
            "period": 60,                           # 周期分钟数
            "node" : 52924,                         # 可以指定在哪个托管者上运行,不写该属性就是自动分配。
            "appid": "member2",                     # 自定义字段
            "exchanges": [
                {"pid": 15445, "pair": "ETH_BTC"},     # ZB  , pid 可以由 GetExchangeList 方法获取到,
                {"pid": 13802, "pair": "BCH_BTC"},     # OKEX
            
            # 除了FMZ控制中心配置好的交易所(pid 识别),还可以设置 没有配置过的交易所 配置信息,用来给机器人操作。
                {"eid": "OKEX", "pair": "ETH_BTC", "meta" :{"AccessKey": "xxx", "SecretKey": "yyy"}},
                {"eid": "Huobi", "pair": "BCH_BTC", "meta" :{"AccessKey": "xxx", "SecretKey": "yyy"}},
            # 注意:
            # eid 识别的 配置中 , "meta" :{"AccessKey": "xxx", "SecretKey": "yyy"} 这些敏感 信息 (API 密钥)
            # FMZ 是不储存的,直接转发给 托管者程序 ,所以每次创建 或者 重启 机器人时,必须 配置该 信息。
            ],
        }
        

        如何创建使用插件支持交易所的机器人: 在配置settings这个参数时,对于 exchanges 属性,可以使用 如下 设置:

        {"eid": "Exchange", "label" : "testOCX", "pair": "ETH_BTC", "meta" :{"AccessKey": "123", "SecretKey": "1234", "Front" : "http://127.0.0.1:6666/OCX"}},
        

        “label” 属性是给当前通用协议接入的交易所对象设置一个标签,在策略中可以使用 GetLabel 函数获取。

        测试用策略:

        策略参数

        Interval

        function main(){
            Log(exchange.GetAccount())
            Log(exchange.GetTicker())
            Log(exchange.GetDepth())
            Log("Interval:", Interval)
        }
        

        返回值

        # 成功创建 机器人。
        {
            "code": 0,
            "data": {
                "result": 74260,
                "error": null
            }
        }
        

        实盘机器人创建并运行

        img

      • 13、method : “PluginRun”

        使用扩展 API 调用 调试工具

        img

        参数 args

        settings 为Object类型。      # 调试工具 中的设置(settings 配置中 包括了 测试代码 code)。
        
        #!/usr/bin/python
        # -*- coding: utf-8 -*-
        import time
        import md5
        import urllib
        import json
        
        accessKey = 'f77XXXXXXXXXXXXXXX757'              # API KEY 已经打码,可用自己的 API KEY 测试
        secretKey = 'd8XXXXXXXXXXXXXXXX41ca97ea15'       # API KEY 已经打码,可用自己的 API KEY 测试
        
        def api(method, *args):
            d = {
                'version': '1.0',
                'access_key': accessKey,
                'method': method,
                'args': json.dumps(list(args)),
                'nonce': int(time.time() * 1000),
                }
            d['sign'] = md5.md5('%s|%s|%s|%d|%s' % (d['version'], d['method'], d['args'], d['nonce'], secretKey)).hexdigest()
            return json.loads(urllib.urlopen('https://www.fmz.com/api/v1', urllib.urlencode(d)).read())
        
        code = '''
        function main() {
            Log(exchange.GetTicker())
            exchange.SetTimeout(2000);
            return exchanges[0].GetTicker()
        }
        '''
        
        settings = { 
            "period": 60, 
            "source": code, 
            "node" : 54913,                        #  托管者 ID ,可以指定在哪个托管者上运行机器人, 如果该值 为 -1 ,代表自动分配。 
            "exchanges": [
                {"eid": "OKEX", "pair": "ETH_BTC", "meta" :{"AccessKey": "123abc", "SecretKey": "123abc"}},
                {"eid": "Huobi", "pair": "BCH_BTC", "meta" :{"AccessKey": "123abc", "SecretKey": "123abc"}},
            ]
        }
        
        print api("PluginRun", settings)
        

        {“eid”: “OKEX”, “pair”: “ETH_BTC”, “meta” :{“AccessKey”: “123abc”, “SecretKey”: “123abc”}}, {“eid”: “Huobi”, “pair”: “BCH_BTC”, “meta” :{“AccessKey”: “123abc”, “SecretKey”: “123abc”}}, 注意 settings 在调试工具中只用设置一个(在调试工具页面使用时也只支持添加一个) 在 settings 里设置2个交易所对象不会引起报错,但是在代码中如果访问第二个交易所对象就会报错误。

        api(“PluginRun”, settings) 返回结果

        {
            u'code': 0, 
            u'data': {
                u'result': u'{"logs":[{"PlatformId":"","OrderId":"0","LogType":5,"Price":0,"Amount":0,"Extra":"{\\"Info\\":{\\"date\\":\\"1523715057\\",\\"ticker\\":{\\"high\\":\\"0.06400845\\",\\"vol\\":\\"117648.31546800\\",\\"last\\":\\"0.06204514\\",\\"low\\":\\"0.06178666\\",\\"buy\\":\\"0.06200001\\",\\"sell\\":\\"0.06208728\\"}},\\"High\\":0.06400845,\\"Low\\":0.06178666,\\"Sell\\":0.06208728,\\"Buy\\":0.06200001,\\"Last\\":0.06204514,\\"Volume\\":117648.315468,\\"OpenInterest\\":0,\\"Time\\":1523715057726}","Instrument":"","Direction":"","Time":1523715057726}],"result":"{\\"Info\\":{\\"date\\":\\"1523715057\\",\\"ticker\\":{\\"vol\\":\\"117648.31546800\\",\\"last\\":\\"0.06204514\\",\\"low\\":\\"0.06178666\\",\\"buy\\":\\"0.06200001\\",\\"sell\\":\\"0.06208728\\",\\"high\\":\\"0.06400845\\"}},\\"High\\":0.06400845,\\"Low\\":0.06178666,\\"Sell\\":0.06208728,\\"Buy\\":0.06200001,\\"Last\\":0.06204514,\\"Volume\\":117648.315468,\\"OpenInterest\\":0,\\"Time\\":1523715057774}"}\n', 
                u'error': None
            }
        }
        
      • 14、method : GetRobotLogs

        获取指定ID机器人的日志信息

        参数 args

            robotId 为int类型,               # 机器人ID
        # table Log ,查询数据库表 Log 的数据     
            logMinId 为int类型,              # Log 日志的 最小 ID
            logMaxId 为int类型,              # Log 日志的 最大 ID
            logOffset 为int类型,             # 由 logMinId 和 logMaxId 确定 范围后, 根据 logOffset 偏移(跳过多少条记录),开始作为获取数据的起始位置。
            logLimit 为int类型,              # 确定起始位置后,选取的数据记录条数。
        # table Profit , 查询数据库表 Profit 的数据
            profitMinId 为int类型,           # 记录 最小ID
            profitMaxId 为int类型,           # 记录 最大ID
            profitOffset 为int类型,          # 偏移(跳过多少条记录),作为起始 位置
            profitLimit 为int类型,           # 确定起始位置后,选取的数据记录条数。
        # table Chart, 查询数据表 Chart 的数据
            chartMinId 为int类型,            # 记录 最小ID
            chartMaxId 为int类型,            # 记录 最大ID
            chartOffset 为int类型,           # 偏移
            chartLimit 为int类型,            # 需要获取的记录条数
            chartUpdateBaseId 为int类型,     # 查询的更新后的基础ID ,
            chartUpdateDate 为int类型,       # 数据记录更新时间戳,会筛选出 比这个时间戳大的 记录。 
        
        # 调用 范例:
        api('GetRobotLogs', 63024, 0, 0, 7, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)    # 具体代码,参看以上内容: 4、简单的例子,此处不再赘述,只写 GetRobotLogs 的调用 和 参数传入。
        

        返回数据:

        {
            "code": 0,
            "data": {
                "result": {
                    "status": 1,
                    "updateTime": 1527049990197,
                    "wd": 0,
                    "logs": [{
                        "Max": 3984,
                        "Arr": [
                            [3977, 3, "Futures_OKCoin", "", 0, 0, "Sell(688.9, 2): 20016", 1526954372591, "", ""],
                            [3976, 5, "", "", 0, 0, "OKCoin:this_week 仓位过多, 多: 2", 1526954372410, "", ""]
                        ],
                        "Total": 1503,
                        "Min": 2482
                    }, {
                        "Max": 0,
                        "Arr": [],
                        "Total": 0,
                        "Min": 0
                    }, {
                        "Max": 0,
                        "Arr": [],
                        "Total": 0,
                        "Min": 0
                    }],
                    "chart": "",
                    "refresh": 1527049988000,
                    "summary": "...", 
                    "chartTime ": 0, 
                    "node_id ": 50755, 
                    "online ": true
                }, 
                "error ": null
            }
        }
        

        查询的日志截图: img

        以上返回结果数据中 Arr 属性值 描述:

        "Arr": [
            [3977, 3, "Futures_OKCoin", "", 0, 0, "Sell(688.9, 2): 20016", 1526954372591, "", ""],
            [3976, 5, "", "", 0, 0, "OKCoin:this_week 仓位过多, 多: 2", 1526954372410, "", ""]
        ],
        
        id logType eid orderId price amount extra date contractType direction
        3977 3 “Futures_OKCoin” "" 0 0 “Sell(688.9, 2): 20016” 1526954372591 "" ""
        3976 5 "" "" 0 0 “OKCoin:this_week 仓位过多, 多: 2” 1526954372410 "" ""
        • extra 为 打印日志,附加消息。

        • logType 值具体代表的日志类型:

          logType: 0 1 2 3 4 5 6
          logType意义: BUY SALE RETRACT ERROR PROFIT MESSAGE RESTART
          中文意义 买单类型日志 卖单类型日志 撤销 错误 收益 日志 重启
  • 5. 废弃的API

    由于之前一些 数据是内置的,交易所经常调整,并且无法实时获取(大部分交易所没有提供获取接口)。所以为了策略更加合理,一些数值最好设置为策略参数,以便实时调整,例如:数字货币 交易手续费 。

    废弃的 数据结构

    • Fee 手续费结构

    废弃的 API 函数

    • GetFee() 获取 手续费, 已经废弃。

    • GetMinPrice() 获取 最小交易额度 已经废弃。

    • GetMinStock() 获取 最小交易量 已经废弃。

  • 6. 其它

    • 协议: 数字货币 WebSocket 协议

      交易所 备注
      OKEX V1 支持 WebSocket 协议后,就无法使用 代码 exchange.IO("currency", “ETH”) 切换币种功能(切换为 以太币)
      火币 支持 WebSocket 协议后,就无法使用 代码 exchange.IO("currency", “ETH”) 切换币种功能
    • 交易所杠杆账户模式:

      切换为杠杠账户模式

      使用 exchange.IO("trade_margin") 切换为杠杠账户模式,下单、获取账户资产 将访问交易所杠杆接口。 使用 exchange.IO("trade_normal") 切换回普通账户模式。

      支持的交易所:

      交易所 备注
      OKEX V3 杠杆账户模式的交易对和普通的有所不同,有些交易对可能没有。
      火币 杠杆账户模式的交易对和普通的有所不同,有些交易对可能没有。
    • 托管者已经定义的功能函数

      • 1、onexit() 扫尾函数

        处理扫尾工作,最长执行5分钟,由用户实现。

        javascript

        function main(){
            Log("开始运行, 5秒后 停止,并执行扫尾函数!")
            Sleep(1000 * 5)
        }
        
        // 扫尾函数实现
        function onexit(){
            var beginTime = new Date().getTime()
            while(true){
                var nowTime = new Date().getTime()
                Log("程序停止倒计时..扫尾开始,已经过去:", (nowTime - beginTime) / 1000, "秒!")
                Sleep(1000)
            }
        }
        

        img

      • 2、init() 初始化函数

        用户实现 初始化函数 init ,会在策略开始时 自动执行 init 函数,完成初始化任务。

        javascript

        function main(){
            Log("程序第一行代码执行!", "#FF0000")
            Log("退出!")
        }
        
        function init(){     // 初始化函数 
            Log("初始化!")
        }
        

        img


More

sajshuai 新手刚接触FMZ,模拟时_C(exchange.GetRecords, PERIOD_H1)只能返回前101个数据,PERIOD_D1只返回了11条数据,不能用于完整的计算整个指标。想问下有什么办法可以完整的获取全部数据么?或者根据指定日期来获取

haiwwhai _C(function, args...) 这个默认是3s吗? 修改默认直接放_CDelay(1000) 在_C(function, args...) 之前就可以了吗?设定一次就可以了吧?

lanchaiye 集群: 如果你创建1000个机器人并发,也是没有压力的, 可以创建多个托管者来分散任务 有代码例子来建集群?如何建多个托管者来分散任务

黑马王子 Record和Ticker 很多内容很相似,到底有什么不同,用在什么场合为好了?

wangyj1 Log(talib.help('MACD'));只能在js下使用,python下没有talib.help属性...

cjz140 _C(function, args…) 和Sleep 函数有什么区别呢,我觉得都是等待重试的意思

3263243y SetErrorFilter 后怎么清空 ErrorFilter?不过滤错误信息。

qq47898077 如果想用第三方库有什么办法吗?

qq47898077 如果想继承交易所对象定义新的类的话,父类应该填什么呢。

wyx API文档好难看 有没有模板代码 就一个main

ethanwu 有本地调试工具吗?

pengliheng 那exange.IO("status")呢?

pengliheng 为什么sell的函数是灰色的,是不是代表函数不可用了?by是可用的,那要如何卖呢

pengliheng 为什么sell的函数是灰色的,是不是代表函数不可用了?by是可用的,那要如何卖呢

pengliheng js没白学,哈哈哈,就想问问es6支持么

pengliheng js没白学,哈哈哈,就想问问es6支持么

Don. Volume的均线要怎么写出来?

zjuturtle 按市价购买exchange.Buy(1000)如果不成功会返回什么?

langpanf 怎么这么难

langpanf 怎么这么难

宁公子 这个新字体好看~

wzxa2458 Bitmex的测试网络(testnet.bitmex.com)同样存在API接口,但目前交易所只能选Bitmex主站,API文档地址是 https://testnet.bitmex.com/app/apiOverview 请问如何支持?

cxjijin var ret1 = exchanges[0].IO("api", "future_estimated_price", "symbol=btc_usd"); Log('ok期货预估交割价格', ret1); https://dn-filebox.qbox.me/d1ed268c1e75753c5d289447d279aa9d81e41b5f.png 调用其他交易所功能接口,这么写报错,是为什么呢?

allenfrostline 想问realTicker和Ticker有什么区别?最近在重写套利的策略,同时出现了这两个但前者API里似乎没有提到

visions 你好 作为一个python开发者 觉得你们的api文档写的是什么东西?一些字段函数接口看得莫名其妙的,能不能像githubpage和readdocs这样写一份文档?

allenfrostline GetAccount: [EAPI:Rate limit exceeded] 想问这个怎么解决?另外我没有qq有没有微信群之类的?感谢

tino BITMEX not supported ? i mean future exchange, thanks for reply

tino BITMEX not supported ?

piccolo247 I can't setup the bot to trade on cryptocurren ies. Can anyone help me do that? Mirror trading will be a useful step. Is anybody willing to be my mentor? Or help me manage my account?

yermin 托管者为啥不支持32位 Linux

wangxindiy // 策略采用轮询而非事件驱动是因为作者喜欢对代码100%的掌控力. 好吧。这句话实在不理解。。。。。就是评论一下

zhjx2314 不支持StochRSI,是否可以尽快添加

__fy [ ORDER_STATE_PENDING :未完成 ORDER_STATE_CLOSED :已关闭 ORDER_STATE_CANCELED :已取消 ] OKCOIN-status: -1:已撤销 0:未成交 1:部分成交 2:完全成交 4:撤单处理中 HUOBI-status: 0未成交 1部分成交 2已完成 3已取消 4废弃(该状态已不再使用) 5异常 6部分成交已取消 7队列中 这三种状态是如何对应的?

yhfgg python策略实盘的时候脚本是在自己的阿里云服务器还是botvs集群?

yhfgg python用的什么版本?

fkysly GetFee 的 解释应该是”返回一个Fee结构”吧,少了一个构字。

zkwap 使用js能调用talib的方法吗

yhfgg 求python文档

simtech2win Python量化策略回测研发 来到这里,震撼!

bitsbetter 新手上路,请多关照。

wmjbs123 策略编辑的代码背景能不能搞个黑色的?白色的刺眼,晚上写代码,容易近视

Don. 机器人微信推送中的概要 该怎么设置??

数·狂 订单(Order)结构里能不能加一个成交均价的字段?

小丁丁 GetOrders:获取所有未完成的订单, 返回一个Order数组结构, 在中国比特币交易ETH ,只返回最近的10条 ,这里有返回中国比特币ETH所有未完成的订单的函数吗,表示其它平台都可以用GetOrders返回所有的 ,只有这个鬼中国比特币返回10条,

yhfgg 需要用到统计概率论的数学函数,从哪里用呢?

Gavin 请问群号多少?

jiebang $.Cross(x, y)这个函数的返回值是啥意思?

qdk0901 $.Cross(x, y)这个函数是什么鬼,api文档里怎么不说明啊

我的昵称 这个 LogReset 清空所有日志, 可以带一个数字参数, 指定保留的条数 这个要怎么删除最新的几条日志?

edwardgyw talib 中CORRE函数好像没有移植过来 是漏掉了么?

逐浪蚊子 上穿,下穿,相交 这些函数没有找到。

穷山僻壤 貌似没有指标引用的功能!有吗

小小 读取的k线时间怎么翻译成现在时间啊,看不懂,太长的一个,解决了,谢谢

小小 数组中的数删除怎么写,我用records.remove(records[0])好像不行啊

snakeayu 平常获取的是小时K线,如何调用日K线的ATR?

snakeayu 平常获取的是小时K线,如何调用日K线的ATR?

57278863 学习一下传统期货怎么获得价格和下单,不好意思,根基很薄

kirin 同求传统期货交易例子!

小小 zero,能写个关于传统期货交易的例子吗

小小 多空单子同时持有的时候,如何打印持仓状态,我的怎么打印的是[object object][object object],怎么获得多单和空单持仓状况啊,还有GetTicker(),当周,次周,和季度怎么都得到当周 价格,括号中的当周,次周和季度我都写了。

cxjijin 期货交易所可以用GetTicker()获取行情吗?, 返回的是那种类型的合约行情(当周、次周..)?

卖大 StochRSI 这个什么指标,能添加吗?

momox CancelOrder(orderId) 根据订单号取消一个订单, 返回true或者false ,请问 true=单子被成功取消,对吧?

momox _G(K, V) 可保存的全局字典表 这个方法保存的全局变量,可以用于不同策略之间的数据共享吗?

flufy3d 冲冲人气

Zero 可以用LogProfitReset重置下收益日志. 之前的收益图表上的历史就没有了.

xcy 能不能直接复制EA过来用

sjironman 感觉这个平台棒棒哒,多在群里交流哈

小小 这是什么语言,有学习资料吗

murphy 请问, 你说的支持异步的这些操作是什么意思?这样难道不会造成自成交吗?

jamesbd PF,PF

jxhbtc Data error 一个星期 一直连接不了机器人 怎么解决

dyhhu 指标库TA,只是对收盘价进行计算吗?

btcrobot hi, world

小小梦 持续 获取 K线数据, 累积足够的数据量开始计算指标。策略广场有些 指标策略 里面有范例,可以看下

小小梦 python 的 talib 库 需要 安装一下。https://www.botvs.com/bbs-topic/669 可以参看 这个 帖子。

小小梦 Sleep 是 程序什么也不做,等待 参数设定的 毫秒数, _C 是重新调用一次 参数 传入的 函数。

小小梦 不用继承, JS 直接 封装在对象就行了 {name : "新对象", old_exchange : exchange[0], ...... }

小小梦 有本地 编辑器 远程同步插件,基本算是 本地编辑 远程调试。

小小梦 有的,在策略广场有 策略框架 模板, 也有策略基本结构范例,可以找下。另外论坛里面 好几个 策略的注释版 。

小小梦 可以来 QQ群,^^ 方便讨论~

小小梦 API文档上 灰色的意思是 这个 函数 没有过多的展开解释,就显示灰色,蓝色的代表 有更多的解释,仅此而已。

小小梦 ES6暂时不支持, ^^

小小梦 可以 到群里QQ 我,问题描述一下,我来解答 ^^

小小梦 直接会返回 一个错误 ,并且 不会下单(其实就是 要买,钱不够!)。

zjuturtle 比如OKCoin,如果购买的量超过了持有的人民币,会返回什么?

小小梦 具体是 哪个交易所呢,我在OK期货会返回一个订单号。

小小梦 您好 请问 有什么问题, 初学BotVS 可以看下 置顶的教程附带有视频讲解。

Zero 已经支持运行时切换交易对, 需下载最新托管者. 支持Bter/Poloniex 详情 API文档 交易函数栏下面的描述(清空浏览器缓存后刷新如果看不到)

小小梦 QQ我吧,我帮您找下问题。359706687

职业养鸡户 需要设置白名单, 我设置的是托管机子的IP?

小小梦 这个是 底层链接 没有建立 服务器没响应。API KEY 申请的时候 有要设置 IP地址么?

职业养鸡户 这就尴尬了···我ok可以跑的策略换到比特时代就失灵了,GetAccount 都获取不到 GetAccount: Post http://api.btc38.com/v1/getMyBalance.php: read tcp 192.168.0.227:58596->211.149.148.144:80: wsarecv: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. 2017-05-23 21:08:24 比特时代 错误 GetAccount: timeout 2017-05-23 21:08:02 比特时代 错误 GetAccount: timeout 2017-05-23 21:07:40 比特时代 错误 GetAccount: timeout 2017-05-23 21:07:20 重启 是不是 IP白名单的问题???

小小梦 交易所的 服务器 没有响应了,TCP协议 三次握手都没有建立。

职业养鸡户 不知道为什么策略用到比特时代的话会一直报这个错 A connection attempt failed because the connected party did not properly respond after a period of time,

小小梦 您好! 说的是 exchange.IO(“api”, ApiName, Args) 这个函数 不支持, 参见 https://www.botvs.com/bbs-topic/812

职业养鸡户 A connection attempt failed because the connected party did not properly respond after a period of time,

职业养鸡户 比特时代不支持吗

小小梦 https://dn-filebox.qbox.me/a709b30c6cc0a3565234b9e0c99b073f7ba8b454.png 应该是可以的。

宁公子 比如我想做个poloniex 的全币种交易,但是BOTvs 支持的币种只有几个,exchange.IO貌似是不支持P网的。

小小梦 可以调用 exchange.IO 这个。

宁公子 需要验证账户的 API 的呢?

小小梦 如果不需要验证账户的 API 可以使用 httpQuery (详见 BotVS 文档), 实际交易 API 需要接入。

小小梦 可以使用 HttpQuery 这个 API 参数传:https://www.okcoin.com/api/v1/future_estimated_price.do?symbol=btc_usd ,这样就可以了。 对于 不用验证 账户的 行情类的 交易所 API 直接就用 平台上的 HttpQuery 这个函数, 那些 跟账户相关的 才用 IO 这个API (IO 不支持这些 不需要验证的行情API )。 帖子 : https://www.botvs.com/bbs-topic/850

visions 好的谢谢,期望能有完善优美的API文档。

小小梦 请问 realTicker 这个API 是在什么地方看到的?

小小梦 https://dn-filebox.qbox.me/fe1a6f5563ed43a5357f858ecf8a50239619228e.png API文档 是JavaScript 语言 描述的,python 版描述的在 “交流社区” 页面置顶的帖子。(如有具体问题欢迎留言提出)

Zero 你好, 多谢建议, 目前API文档正在重构中.

小小梦 您好~显示的是 访问频率超出限制。 https://dn-filebox.qbox.me/a09498920d04cac62624b7438a058d2098d8fb00.png 策略中使用Sleep(1000) 函数了么 ? , 这个1000就是 让程序每轮暂停一秒,可以自行设置,目的就是控制程序 访问API 的频率,因为有些交易所设置了最大访问限制,一定时间超过一定访问次数会拒绝访问,封掉IP地址。

小小梦 Excuse me, We are planning to support BITMEX .

小小 you can qq call 小小梦,add his qq 1521288475,then he let zero add this exchange

小小梦 Welcome to BotVS ,This video is what you need . address is : http://v.youku.com/v_show/id_XMjUxMTc5Nzc5Ng==.html?f=29474416&from=y1.7-3&spm=a2hzp.8253876.0.0 if you need help , you can call me on QQ, my number is 1521288475 。

小小梦 可能 这个版本的性能 不如 64 的。

小小梦 https://dn-filebox.qbox.me/c29ab7fc279e1b758355f137907cf52dc8257df6.png 我个人写的 已经对比过OK 的STOCHRSI指标 ,一致 ,就是速度有些慢有待优化,暂时可用。https://www.botvs.com/bbs-topic/392

小小梦 火币: ORDER_STATE_PENDING: 挂单没有完全成交,或者 没有成交。 对应0、1 、7 ORDER_STATE_CLOSED: 完全成交, 对应 2 ORDER_STATE_CANCELED: 3、6

Zero 可以自己选择是在botvs提供的服务器上回测还是自己的托管者所在服务器回测, 版本是2.7.5

小小梦 现已添加。

小小梦 现在已经可以自己配置 背景风格了。

小小梦 python 文档正在写。

小小梦 可以的 talib 库支持。

hzzgood48 https://www.botvs.com/bbs-topic/276

小小梦 貌似在策略广场有例子,https://www.botvs.com/strategy/15098

Zero 访问Order的AvgPrice属性, 交易所支持可以, 不支持的交易所会一直为0这个属性

yhfgg 第三方库怎么引用?

Zero mathjs看能满足不能, 不能就只能找第三方库复制进策略了. 为了编译速度, 系统只内置了一些少量的库.

小小梦 309368835 官方QQ群

小小梦 不客气,有问题在群里可以M我~我基本都在线。

jiebang 谢谢

小小梦 在群里么?你可以看看注释版的 数字货币交易类库代码分析 里面就有 $.Cross函数的注释

jiebang Cross(x, y)这个函数的返回值是啥意思?

小小梦 这个函数 不是平台的API, 是群主写的一个模板的导出函数。

Zero 不能删除最新的,只能保留最新的几条..删除之前所有老的.

逐浪蚊子 上穿用这种是不对的,我们需要的是一个点。如果用他会无休止的循环加仓。

wsnrag 这个要自己写的,比如MA(RECORDS,5)>MA(RECORDS,15)就是上穿

kirin 要用position[i]获取每个持仓,position是个数组

宁公子 exchange.GetRecords(PERIOD_D1);

kirin 我的传统期货老是报“GetAccount: not login",密码没有输错,就是登陆不了

Zero 默认是周, 要获取指定的需要SetContractType先.

Zero 刚看到,这个true是交易所返回的取消订单这个动作的返回值, 但真正取消没取消,得看交易所内部怎么处理了.

momox 3q

Zero 暂时不能, 是隔离的.

xuanxuan 当然不能,那是MT4的专用吧

Zero 策略广场里有很多开源的可以看

Zero Javascript 资料网上到处都有哈

卖大 你的问题解决了吗?

卖大 有教程吗,我是新手,初学策略编写,困难重重,希望指教。

Zero 大部分是, 传入的数据可以直接是records或者是一个纯价格的数组