发明者量化API文档

Author: 小小梦, Created: 2017-11-27 09:05:08, Updated: 2023-07-12 16:47:31

已经收到了数据,后续才开始EventLoop监听机制,就错过了这些事件 // 除非在第一行代码开始调用EventLoop(-1),首先初始化EventLoop的监听机制,则不会错过这些事件

// Log("GetDepth:", routine_getDepth.wait()) 如果这里提前调用wait函数取出GetDepth函数并发调用的结果,此次GetDepth函数收到请求结果的事件便不会在EventLoop函数返回
var ts1 = new Date().getTime()
var ret1 = EventLoop(0)

var ts2 = new Date().getTime()
var ret2 = EventLoop(0)

var ts3 = new Date().getTime()
var ret3 = EventLoop(0)

Log("第1个并发任务完成的为:", _D(ts1), ret1)
Log("第2个并发任务完成的为:", _D(ts2), ret2)
Log("第3个并发任务完成的为:", _D(ts3), ret3)

Log("GetTicker:", routine_getTicker.wait())
Log("GetDepth:", routine_getDepth.wait())
Log("GetTrades:", routine_getTrades.wait())

}


```python
import time
def main():
    routine_getTicker = exchange.Go("GetTicker")
    routine_getDepth = exchange.Go("GetDepth")
    routine_getTrades = exchange.Go("GetTrades")
    
    ts1 = time.time()
    ret1 = EventLoop(0)
    
    ts2 = time.time()
    ret2 = EventLoop(0)
    
    ts3 = time.time()
    ret3 = EventLoop(0)
    
    Log("第1个并发任务完成的为:", _D(ts1), ret1)
    Log("第2个并发任务完成的为:", _D(ts2), ret2)
    Log("第3个并发任务完成的为:", _D(ts3), ret3)
    
    Log("GetTicker:", routine_getTicker.wait())
    Log("GetDepth:", routine_getDepth.wait())
    Log("GetTrades:", routine_getTrades.wait())
void main() {
    auto routine_getTicker = exchange.Go("GetTicker");
    auto routine_getDepth = exchange.Go("GetDepth");
    auto routine_getTrades = exchange.Go("GetTrades");
    
    auto ts1 = Unix() * 1000;
    auto ret1 = EventLoop(0);
    
    auto ts2 = Unix() * 1000;
    auto ret2 = EventLoop(0);
    
    auto ts3 = Unix() * 1000;
    auto ret3 = EventLoop(0);
    
    Log("第1个并发任务完成的为:", _D(ts1), ret1);
    Log("第2个并发任务完成的为:", _D(ts2), ret2);
    Log("第3个并发任务完成的为:", _D(ts3), ret3);
    
    Ticker ticker;
    Depth depth;
    Trades trades;
    routine_getTicker.wait(ticker);
    routine_getDepth.wait(depth);
    routine_getTrades.wait(trades);
    
    Log("GetTicker:", ticker);
    Log("GetDepth:", depth);
    Log("GetTrades:", trades);
}

内置函数

_G(K, V)

_G(K, V),该函数实现了一个可保存的全局字典功能,回测和实盘均支持。回测结束后,保存的数据会被清除。 数据结构为KV表,永久保存在本地文件,每个实盘单独一个数据库,重启或者托管者退出后一直存在。K必须为字符串,不区分大小写,V可以为任何可以JSON序列化的内容。在实盘运行中当调用_G()函数并且不传任何参数时,_G()函数返回当前实盘的ID

function main(){
    // 设置一个全局变量num,值为1
    _G("num", 1)     
    // 更改一个全局变量num,值为字符串ok
    _G("num", "ok")    
    // 删除全局变量num
    _G("num", null)
    // 返回全局变量num的值
    Log(_G("num"))
    // 删除所有全局变量
    _G(null)
    // 返回实盘ID
    var robotId = _G()
}
def main():
    _G("num", 1)     
    _G("num", "ok")    
    _G("num", None)
    Log(_G("num"))
    _G(None)
    robotId = _G()
void main() {
    _G("num", 1);
    _G("num", "ok");
    _G("num", NULL);
    Log(_G("num"));
    _G(NULL);
    // 不支持 auto robotId = _G();
}

注意: 使用_G函数持久化储存数据时,应当根据硬件设备的内存、硬盘空间合理使用,不可滥用。否则可能造成内存溢出的问题。

_D(Timestamp, Fmt)

_D(Timestamp, Fmt),返回指定时间戳对应的时间字符串。参数值:Timestamp为数值类型,值为毫秒数。Fmt为字符串类型,Fmt默认为:yyyy-MM-dd hh:mm:ss,返回值:字符串类型。 返回指定时间戳(毫秒)对应的字符串,不传任何参数就返回当前时间。例如:_D()或者_D(1478570053241),默认格式为yyyy-MM-dd hh:mm:ss

function main(){
    var time = _D()
    Log(time)
}
def main():
    strTime = _D()
    Log(strTime)
void main() {
    auto strTime = _D();
    Log(strTime);
}

注意: Python策略中使用_D()时,需要注意传入的参数为秒级别时间戳(JavaScriptC++策略中为毫秒级别时间戳,1秒等于1000毫秒)。 在实盘时使用_D()函数解析一个时间戳为可读的时间字符串时,需要注意托管者程序所在的操作系统的时区、时间设置。_D()函数解析一个时间戳为可读时间字符串是根据托管者系统的时间而定的。

例如一个时间戳为1574993606000使用代码解析:

function main() {
    Log(_D(1574993606000))
}
def main():
    # 北京时间的服务器上运行:2019-11-29 10:13:26 ,另一台其它地区的服务器上的托管者运行此代码结果则为:2019-11-29 02:13:26
    Log(_D(1574993606))
void main() {
    Log(_D(1574993606000));
}

_N(Num, Precision)

_N(Num, Precision),格式化一个浮点数。参数值:Num为数值类型,Precision为整型。返回值:数值类型。

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

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

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

function main(){
    var i = 1300
    Log(i)
    var ii = _N(i, -3)
    // 查看日志得知为1000
    Log(ii)
}
def main():
    i = 1300
    Log(i)
    ii = _N(i, -3)
    Log(ii)
void main() {
    auto i = 1300;
    Log(i);
    auto ii = _N(i, -3);
    Log(ii);
}

_C(…)

_C(function, args...),该函数为重试函数,用于获取行情、获取未完成订单等接口的容错。

该接口会一直调用指定函数直到成功返回(参数function引用的函数调用时返回空值或者false会重试调用)。例如_C(exchange.GetTicker),默认重试间隔为3秒,可以调用_CDelay(...)函数来设置重试间隔,例如_CDelay(1000),指改变_C函数重试间隔为1秒。

对于以下函数:

  • exchange.GetTicker()
  • exchange.GetDepth()
  • exchange.GetTrades()
  • exchange.GetRecords()
  • exchange.GetAccount()
  • exchange.GetOrders()
  • exchange.GetOrder()
  • exchange.GetPosition()

都可以通过_C(...)函数来调用进行容错。_C(function, args...)函数不局限于以上列出的函数容错,参数function是函数引用并非函数调用,注意是_C(exchange.GetTicker)并不是_C(exchange.GetTicker())

function main(){
    var ticker = _C(exchange.GetTicker)
    // 调整_C()函数重试时间间隔为2秒
    _CDelay(2000)
    var depth = _C(exchange.GetDepth)
    Log(ticker)
    Log(depth)
}
def main():
    ticker = _C(exchange.GetTicker)
    _CDelay(2000)
    depth = _C(exchange.GetDepth)
    Log(ticker)
    Log(depth)
void main() {
    auto ticker = _C(exchange.GetTicker);
    _CDelay(2000);
    auto depth = _C(exchange.GetDepth);
    Log(ticker);
    Log(depth);
}

对于有参数的函数使用_C(...)容错时:

function main(){
    var records = _C(exchange.GetRecords, PERIOD_D1)
    Log(records)
}
def main():
    records = _C(exchange.GetRecords, PERIOD_D1)
    Log(records)
void main() {
    auto 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)
}
import time
def test(a, b):
    ts = time.time()
    if ts % b == 3:
        Log("符合条件!", "#FF0000")
        return True
    Log("重试!", "#FF0000")
    return False

def main():
    ret = _C(test, 1, 5)
    Log(ret)
// C++ 不支持这种方式对于自定义函数容错

_Cross(Arr1, Arr2)

_Cross(Arr1, Arr2),返回数组arr1arr2的交叉周期数。正数为上穿周期,负数表示下穿的周期,0指当前价格一样。参数值:数值类型数组。

可以模拟一组数据测试_Cross(Arr1, Arr2)函数:

// 快线指标
var arr1 = [1,2,3,4,5,6,8,8,9]
// 慢线指标
var arr2 = [2,3,4,5,6,7,7,7,7]
function main(){
    Log("_Cross(arr1, arr2) : ", _Cross(arr1, arr2))
    Log("_Cross(arr2, arr1) : ", _Cross(arr2, arr1))
}
arr1 = [1,2,3,4,5,6,8,8,9]     
arr2 = [2,3,4,5,6,7,7,7,7]
def main():
    Log("_Cross(arr1, arr2) : ", _Cross(arr1, arr2))
    Log("_Cross(arr2, arr1) : ", _Cross(arr2, arr1))
void main() {
    vector<double> arr1 = {1,2,3,4,5,6,8,8,9};
    vector<double> arr2 = {2,3,4,5,6,7,7,7,7};
    Log("_Cross(arr1, arr2) : ", _Cross(arr1, arr2));
    Log("_Cross(arr2, arr1) : ", _Cross(arr2, arr1));
}

img

把模拟的数据可视化进行观察

img

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

JSONParse(strJson)

JSONParse(strJson),该函数用于解析JSON字符串。可以正确解析包含有较大数值的JSON字符串,会将较大的数值解析为字符串类型。回测系统不支持该函数。

function main() {
    let s1 = '{"num": 8754613216564987646512354656874651651358}'
    Log("JSON.parse:", JSON.parse(s1))    // JSON.parse: {"num":8.754613216564988e+39}
    Log("JSONParse:", JSONParse(s1))      // JSONParse:  {"num":"8754613216564987646512354656874651651358"}
    
    let s2 = '{"num": 123}'
    Log("JSON.parse:", JSON.parse(s2))    // JSON.parse: {"num":123}
    Log("JSONParse:", JSONParse(s2))      // JSONParse:  {"num":123}
}
import json

def main():
    s1 = '{"num": 8754613216564987646512354656874651651358}'
    Log("json.loads:", json.loads(s1))    # json.loads: map[num:8.754613216564987e+39]
    Log("JSONParse:", JSONParse(s1))      # JSONParse:  map[num:8754613216564987646512354656874651651358]
    
    s2 = '{"num": 123}'
    Log("json.loads:", json.loads(s2))    # json.loads: map[num:123]
    Log("JSONParse:", JSONParse(s2))      # JSONParse:  map[num:123]
void main() {
    auto s1 = "{\"num\":8754613216564987646512354656874651651358}";
    Log("json::parse:", json::parse(s1));
    // Log("JSONParse:", JSONParse(s1));   // 不支持该函数
    
    auto s2 = "{\"num\":123}";
    Log("json::parse:", json::parse(s2));
    // Log("JSONParse:", JSONParse(s2));   // 不支持该函数
}

自定义颜色

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

function main() {
    Log("红色", "#FF0000")
}
def main():
    Log("红色", "#FF0000")
void main() {
    Log("红色", "#FF0000");
}

日志信息

实盘运行时日志信息记录在实盘的数据库中,实盘的数据库采用sqlite3数据库,实盘的数据库文件在托管者程序所在设备,数据库文件在托管者程序(robot可执行程序)目录下。例如:ID为130350的实盘数据库文件在../logs/storage/130350这个目录内(..即为robot托管者程序所在目录),数据库文件名为130350.db3。 回测系统中的日志可以在回测结束后,点击回测页面底部右下角的[下载日志]按钮进行下载。 当需要迁移实盘到其它服务器上的托管者时,可以移动实盘的数据库文件(扩展名为db3的数据库文件)到迁移目标服务器上,把文件名设置为平台上对应的实盘ID。这样之前实盘的所有日志信息就不会因为迁移到新设备而丢失。

Log(…)

Log(message),保存一条信息到日志列表。参数值:message可以是任意类型。 如果在字符串后面加上@字符则消息会进入推送队列,推送到当前发明者量化交易平台账号推送设置中配置的邮箱、Telegram、WebHook等(依次打开控制中心页面、右上角账号设置页面、推送设置页面设置绑定)。

注意:

  • 「调试工具」中不支持推送。
  • 「回测系统」中不支持推送。
function main() {
    Log("发明者量化你好 !@")
    Sleep(1000 * 5)
    // 字符串内加入#ff0000,打印日志显示为红色,并且推送消息
    Log("你好, #ff0000@")
}
def main():
    Log("发明者量化你好 !@")
    Sleep(1000 * 5)
    Log("你好, #ff0000@")
void main() {
    Log("发明者量化你好 !@");
    Sleep(1000 * 5);
    Log("你好, #ff0000@");
}

WebHook推送:

使用Golang编写的服务程序DEMO:

package main
import (
    "fmt"
    "net/http"
)

func Handle (w http.ResponseWriter, r *http.Request) {
    defer func() {
        fmt.Println("req:", *r)
    }()
}

func main () {
    fmt.Println("listen http://localhost:9090")
    http.HandleFunc("/data", Handle)
    http.ListenAndServe(":9090", nil)
}

设置WebHookhttp://XXX.XX.XXX.XX:9090/data?data=Hello_FMZ

运行服务程序后,执行策略,策略推送信息:

function main() {
    Log("msg", "@")
}
def main():
    Log("msg", "@")
void main() {
    Log("msg", "@");
}

接收到推送,服务程序打印信息:

listen http://localhost:9090
req: {GET /data?data=Hello_FMZ HTTP/1.1 1 1 map[User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/xx.x.xxxx.xxx Safari/537.36] Accept-Encoding:[gzip]] {} <nil> 0 [] false 1XX.XX.X.XX:9090 map[] map[] <nil> map[] XXX.XX.XXX.XX:4xxx2 /data?data=Hello_FMZ <nil> <nil> <nil> 0xc420056300}

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

function main() {
    Log("`data:image/png;base64,AAAA`")
}
def main():
    Log("`data:image/png;base64,AAAA`")
void main() {
    Log("`data:image/png;base64,AAAA`");
}

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

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

打印的日志自动语言切换 Log函数支持语言切换,Log函数输出文本,会根据平台页面上语言设置自动切换为对应的语言,例如:

function main() {
    Log("[trans]中文|abc[/trans]")
}
def main():
    Log("[trans]中文|abc[/trans]")
void main() {
    Log("[trans]中文|abc[/trans]");
}

LogProfit(Profit)

LogProfit(Profit),记录盈亏值,打印盈亏数值并根据盈亏数值绘制收益曲线。参数值:Profit为数值类型。

该函数如果以字符&结尾,只绘制收益图表,不打印收益日志,例如:LogProfit(10, '&')

LogProfitReset()

LogProfitReset(),清空所有收益日志,可以带一个整数数值参数,指定保留的条数。

function main() {
    // 在收益图表上打印30个点,然后重置,只保留最后10个点
    for(var i = 0; i < 30; i++) {
        LogProfit(i)
        Sleep(500)
    }
    LogProfitReset(10)
}
def main():
    for i in range(30):
        LogProfit(i)
        Sleep(500)
    LogProfitReset(10)
void main() {
    for(int i = 0; i < 30; i++) {
        LogProfit(i);
        Sleep(500);
    }
    LogProfitReset(10);
}

LogStatus(Msg)

LogStatus(Msg),此信息不保存到日志列表里,只更新当前实盘的状态信息,在实盘页面日志区域上方的状态栏显示,可多次调用更新状态。参数值:Msg可以为任意类型。

function main() {
    LogStatus('这是一个普通的状态提示')
    LogStatus('这是一个红色字体的状态提示#ff0000')
    LogStatus('这是一个多行的状态信息\n我是第二行')
}
def main():
    LogStatus('这是一个普通的状态提示')
    LogStatus('这是一个红色字体的状态提示#ff0000')
    LogStatus('这是一个多行的状态信息\n我是第二行')
void main() {
    LogStatus("这是一个普通的状态提示");
    LogStatus("这是一个红色字体的状态提示#ff0000");
    LogStatus("这是一个多行的状态信息\n我是第二行");
}

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

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

状态栏中数据输出示例:

function main() {
    var table = {type: 'table', title: '持仓信息', cols: ['列1', '列2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]}
    // JSON序列化后两边加上`字符,视为一个复杂消息格式(当前支持表格)
    LogStatus('`' + JSON.stringify(table) + '`')                    
    // 表格信息也可以在多行中出现
    LogStatus('第一行消息\n`' + JSON.stringify(table) + '`\n第三行消息')
    // 支持多个表格同时显示,将以TAB显示到一组里
    LogStatus('`' + JSON.stringify([table, table]) + '`')
    
    // 也可以构造一个按钮在表格中,策略用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': '平仓'}) + '`')
}
import json
def main():
    table = {"type": "table", "title": "持仓信息", "cols": ["列1", "列2"], "rows": [["abc", "def"], ["ABC", "support color #ff0000"]]}
    LogStatus('`' + json.dumps(table) + '`')
    LogStatus('第一行消息\n`' + json.dumps(table) + '`\n第三行消息')
    LogStatus('`' + json.dumps([table, table]) + '`')

    table = {
        "type" : "table", 
        "title" : "持仓操作", 
        "cols" : ["列1", "列2", "Action"], 
        "rows" : [
            ["abc", "def", {"type": "button", "cmd": "coverAll", "name": "平仓"}]
        ] 
    }
    LogStatus('`' + json.dumps(table) + '`')
    LogStatus('`' + json.dumps({"type": "button", "cmd": "coverAll", "name": "平仓"}) + '`')
    LogStatus('`' + json.dumps({"type": "button", "class": "btn btn-xs btn-danger", "cmd": "coverAll", "name": "平仓"}) + '`')
void main() {
    json table = R"({"type": "table", "title": "持仓信息", "cols": ["列1", "列2"], "rows": [["abc", "def"], ["ABC", "support color #ff0000"]]})"_json;
    LogStatus("`" + table.dump() + "`");
    LogStatus("第一行消息\n`" + table.dump() + "`\n第三行消息");
    json arr = R"([])"_json;
    arr.push_back(table);
    arr.push_back(table);
    LogStatus("`" + arr.dump() + "`");

    table = R"({
        "type" : "table", 
        "title" : "持仓操作", 
        "cols" : ["列1", "列2", "Action"], 
        "rows" : [
            ["abc", "def", {"type": "button", "cmd": "coverAll", "name": "平仓"}]
        ] 
    })"_json;
    LogStatus("`" + table.dump() + "`");
    LogStatus("`" + R"({"type": "button", "cmd": "coverAll", "name": "平仓"})"_json.dump() + "`");
    LogStatus("`" + R"({"type": "button", "class": "btn btn-xs btn-danger", "cmd": "coverAll", "name": "平仓"})"_json.dump() + "`");
}

设置状态栏按钮的禁用、描述功能:

img

function main() {
    var table = {
        type: "table",
        title: "状态栏按钮的禁用、描述功能测试",
        cols: ["列1", "列2", "列3"], 
        rows: []
    }
    var button1 = {"type": "button", "name": "按钮1", "cmd": "button1", "description": "这是第一个按钮"}
    var button2 = {"type": "button", "name": "按钮2", "cmd": "button2", "description": "这是第二个按钮,设置为禁用", "disabled": true}
    var button3 = {"type": "button", "name": "按钮3", "cmd": "button3", "description": "这是第三个按钮,设置为启用", "disabled": false}
    table.rows.push([button1, button2, button3])
    LogStatus("`" + JSON.stringify(table) + "`")
}
import json
def main():
    table = {
        "type": "table",
        "title": "状态栏按钮的禁用、描述功能测试",
        "cols": ["列1", "列2", "列3"], 
        "rows": []
    }
    button1 = {"type": "button", "name": "按钮1", "cmd": "button1", "description": "这是第一个按钮"}
    button2 = {"type": "button", "name": "按钮2", "cmd": "button2", "description": "这是第二个按钮,设置为禁用", "disabled": True}
    button3 = {"type": "button", "name": "按钮3", "cmd": "button3", "description": "这是第三个按钮,设置为启用", "disabled": False}
    table["rows"].append([button1, button2, button3])
    LogStatus("`" + json.dumps(table) + "`")
void main() {
    json table = R"({
        "type": "table",
        "title": "状态栏按钮的禁用、描述功能测试",
        "cols": ["列1", "列2", "列3"], 
        "rows": []
    })"_json;
    json button1 = R"({"type": "button", "name": "按钮1", "cmd": "button1", "description": "这是第一个按钮"})"_json;
    json button2 = R"({"type": "button", "name": "按钮2", "cmd": "button2", "description": "这是第二个按钮,设置为禁用", "disabled": true})"_json;
    json button3 = R"({"type": "button", "name": "按钮3", "cmd": "button3", "description": "这是第三个按钮,设置为启用", "disabled": false})"_json;
    json arr = R"([])"_json;
    arr.push_back(button1);
    arr.push_back(button2);
    arr.push_back(button3);
    table["rows"].push_back(arr);
    LogStatus("`" + table.dump() + "`");
}

状态栏按钮样式设置:

img

function main() {
    var table = {
        type: "table",
        title: "状态栏按钮样式",
        cols: ["默认", "原始", "成功", "信息", "警告", "危险"], 
        rows: [
            [
                {"type":"button", "class": "btn btn-xs btn-default", "name": "默认"},
                {"type":"button", "class": "btn btn-xs btn-primary", "name": "原始"},
                {"type":"button", "class": "btn btn-xs btn-success", "name": "成功"},
                {"type":"button", "class": "btn btn-xs btn-info", "name": "信息"},
                {"type":"button", "class": "btn btn-xs btn-warning", "name": "告警"},
                {"type":"button", "class": "btn btn-xs btn-danger", "name": "危险"}
            ]
        ]
    }
    LogStatus("`" + JSON.stringify(table) + "`")
}
import json
def main():
    table = {
        "type": "table",
        "title": "状态栏按钮样式",
        "cols": ["默认", "原始", "成功", "信息", "警告", "危险"], 
        "rows": [
            [
                {"type":"button", "class": "btn btn-xs btn-default", "name": "默认"},
                {"type":"button", "class": "btn btn-xs btn-primary", "name": "原始"},
                {"type":"button", "class": "btn btn-xs btn-success", "name": "成功"},
                {"type":"button", "class": "btn btn-xs btn-info", "name": "信息"},
                {"type":"button", "class": "btn btn-xs btn-warning", "name": "告警"},
                {"type":"button", "class": "btn btn-xs btn-danger", "name": "危险"}
            ]
        ]
    }
    LogStatus("`" + json.dumps(table) + "`")
void main() {
    json table = R"({
        "type": "table",
        "title": "状态栏按钮样式",
        "cols": ["默认", "原始", "成功", "信息", "警告", "危险"], 
        "rows": [
            [
                {"type":"button", "class": "btn btn-xs btn-default", "name": "默认"},
                {"type":"button", "class": "btn btn-xs btn-primary", "name": "原始"},
                {"type":"button", "class": "btn btn-xs btn-success", "name": "成功"},
                {"type":"button", "class": "btn btn-xs btn-info", "name": "信息"},
                {"type":"button", "class": "btn btn-xs btn-warning", "name": "告警"},
                {"type":"button", "class": "btn btn-xs btn-danger", "name": "危险"}
            ]
        ]
    })"_json;
    LogStatus("`" + table.dump() + "`");
}

结合GetCommand()函数,构造状态栏按钮交互功能:

function test1() {
    Log("调用自定义函数")
}

function main() {
    while (true) {
        var table = {
            type: 'table',
            title: '操作',
            cols: ['列1', '列2', 'Action'],
            rows: [
                ['a', '1', {
                    'type': 'button',                       
                    'cmd': "CoverAll",                      
                    'name': '平仓'                           
                }],
                ['b', '1', {
                    'type': 'button',
                    'cmd': 10,                              
                    'name': '发送数值'
                }],
                ['c', '1', {
                    'type': 'button',
                    'cmd': _D(),                          
                    'name': '调用函数'
                }],
                ['d', '1', {
                    'type': 'button',
                    'cmd': 'test1',       
                    'name': '调用自定义函数'
                }]
            ]
        }
        LogStatus(_D(), "\n", '`' + JSON.stringify(table) + '`')

        var str_cmd = GetCommand()
        if (str_cmd) {
            Log("接收到的交互数据 str_cmd:", "类型:", typeof(str_cmd), "值:", str_cmd)
            if(str_cmd == "test1") {
                test1()
            }
        }

        Sleep(500)
    }
}
import json
def test1():
    Log("调用自定义函数")

def main():
    while True:
        table = {
            "type": "table", 
            "title": "操作", 
            "cols": ["列1", "列2", "Action"],
            "rows": [
                ["a", "1", {
                    "type": "button", 
                    "cmd": "CoverAll",
                    "name": "平仓"
                }],
                ["b", "1", {
                    "type": "button",
                    "cmd": 10,
                    "name": "发送数值" 
                }], 
                ["c", "1", {
                    "type": "button",
                    "cmd": _D(),
                    "name": "调用函数" 
                }],
                ["d", "1", {
                    "type": "button",
                    "cmd": "test1",
                    "name": "调用自定义函数" 
                }]
            ]
        }

        LogStatus(_D(), "\n", "`" + json.dumps(table) + "`")
        str_cmd = GetCommand()
        if str_cmd:
            Log("接收到的交互数据 str_cmd", "类型:", type(str_cmd), "值:", str_cmd)
            if str_cmd == "test1":
                test1()
        Sleep(500)
void test1() {
    Log("调用自定义函数");
}

void main() {
    while(true) {
        json table = R"({
            "type": "table", 
            "title": "操作", 
            "cols": ["列1", "列2", "Action"],
            "rows": [
                ["a", "1", {
                    "type": "button", 
                    "cmd": "CoverAll",
                    "name": "平仓"
                }],
                ["b", "1", {
                    "type": "button",
                    "cmd": 10,
                    "name": "发送数值" 
                }], 
                ["c", "1", {
                    "type": "button",
                    "cmd": "",
                    "name": "调用函数" 
                }],
                ["d", "1", {
                    "type": "button",
                    "cmd": "test1",
                    "name": "调用自定义函数" 
                }]
            ]
        })"_json;
        table["rows"][2][2]["cmd"] = _D();
        LogStatus(_D(), "\n", "`" + table.dump() + "`");
        auto str_cmd = GetCommand();
        if(str_cmd != "") {
            Log("接收到的交互数据 str_cmd", "类型:", typeid(str_cmd).name(), "值:", str_cmd);
            if(str_cmd == "test1") {
                test1();
            }
        }
        Sleep(500);
    }
}

在构造状态栏按钮进行交互时也支持输入数据,交互指令最终由GetCommand()函数捕获。 给状态栏中的按钮控件的数据结构中增加input项,例如给{"type": "button", "cmd": "open", "name": "开仓"}增加"input": {"name": "开仓数量", "type": "number", "defValue": 1},就可以使按钮在被点击时弹出一个带输入框控件的弹窗(输入框中默认值为1,即defValue设置的数据),可以输入一个数据和按钮命令一起发送。例如以下测试代码运行时,在点击「开仓」按钮后,弹出一个带输入框的弹窗,在输入框中输入111后点击「确定」。GetCommand函数就会捕获消息:open:111

function main() {
    var tbl = {
        type: "table",
        title: "操作",
        cols: ["列1", "列2"],
        rows: [
            ["开仓操作", {"type": "button", "cmd": "open", "name": "开仓", "input": {"name": "开仓数量", "type": "number", "defValue": 1}}],
            ["平仓操作", {"type": "button", "cmd": "coverAll", "name": "全部平仓"}]
        ] 
    }

    LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
    while (true) {
        var cmd = GetCommand()
        if (cmd) {
            Log("cmd:", cmd)
        }
        Sleep(1000)
    }
}
import json

def main():
    tbl = {
        "type": "table", 
        "title": "操作", 
        "cols": ["列1", "列2"],
        "rows": [
            ["开仓操作", {"type": "button", "cmd": "open", "name": "开仓", "input": {"name": "开仓数量", "type": "number", "defValue": 1}}],
            ["平仓操作", {"type": "button", "cmd": "coverAll", "name": "全部平仓"}]
        ]
    }

    LogStatus(_D(), "\n", "`" + json.dumps(tbl) + "`")
    while True:
        cmd = GetCommand()
        if cmd:
            Log("cmd:", cmd)
        Sleep(1000)
void main() {
    json tbl = R"({
        "type": "table", 
        "title": "操作", 
        "cols": ["列1", "列2"],
        "rows": [
            ["开仓操作", {"type": "button", "cmd": "open", "name": "开仓", "input": {"name": "开仓数量", "type": "number", "defValue": 1}}],
            ["平仓操作", {"type": "button", "cmd": "coverAll", "name": "全部平仓"}]
        ]
    })"_json;

    LogStatus(_D(), "\n", "`" + tbl.dump() + "`");
    while(true) {
        auto cmd = GetCommand();
        if(cmd != "") {
            Log("cmd:", cmd);
        }
        Sleep(1000);
    }
}

合并LogStatus(Msg)函数画出的表格内的单元格:

  • 横向合并

    function main() {
        var table = { 
            type: 'table', 
            title: '持仓操作', 
            cols: ['列1', '列2', 'Action'], 
            rows: [ 
                ['abc', 'def', {'type':'button', 'cmd': 'coverAll', 'name': '平仓'}]
            ]
        } 
        var ticker = exchange.GetTicker()
        // 添加一行数据,第一个和第二个单元格合并,并且输出ticker变量在合并后的单元格内
        table.rows.push([{body : JSON.stringify(ticker), colspan : 2}, "abc"])    
        LogStatus('`' + JSON.stringify(table) + '`')
    }
    
    import json
    def main():
        table = {
            "type" : "table",
            "title" : "持仓操作",
            "cols" : ["列1", "列2", "Action"],
            "rows" : [
                ["abc", "def", {"type": "button", "cmd": "coverAll", "name": "平仓"}]
            ]
        }
        ticker = exchange.GetTicker()
        table["rows"].append([{"body": json.dumps(ticker), "colspan": 2}, "abc"])
        LogStatus("`" + json.dumps(table) + "`")
    
    void main() {
        json table = R"({
            "type" : "table",
            "title" : "持仓操作",
            "cols" : ["列1", "列2", "Action"],
            "rows" : [
                ["abc", "def", {"type": "button", "cmd": "coverAll", "name": "平仓"}]
            ]
        })"_json;
    
        auto ticker = exchange.GetTicker();
        json jsonTicker = R"({"Buy": 0, "Sell": 0, "High": 0, "Low": 0, "Volume": 0, "Last": 0, "Time": 0})"_json;
        jsonTicker["Buy"] = ticker.Buy;
        jsonTicker["Sell"] = ticker.Sell;
        jsonTicker["Last"] = ticker.Last;
        jsonTicker["Volume"] = ticker.Volume;
        jsonTicker["Time"] = ticker.Time;
        jsonTicker["High"] = ticker.High;
        jsonTicker["Low"] = ticker.Low;
    
        json arr = R"([{"body": {}, "colspan": 2}, "abc"])"_json;
        arr[0]["body"] = jsonTicker;
        table["rows"].push_back(arr);
        LogStatus("`" + table.dump() + "`");
    }
    

  • 纵向合并

    function main() {
        var table = { 
            type: 'table', 
            title: '表格演示', 
            cols: ['列A', '列B', '列C'], 
            rows: [ 
                ['A1', 'B1', {'type':'button', 'cmd': 'coverAll', 'name': 'C1'}]
            ]
        } 
    
        var ticker = exchange.GetTicker()
        var name = exchange.GetName()
    
        table.rows.push([{body : "A2 + B2:" + JSON.stringify(ticker), colspan : 2}, "C2"])
        table.rows.push([{body : "A3 + A4 + A5:" + name, rowspan : 3}, "B3", "C3"])
        // A3被上一行第一个单元格合并
        table.rows.push(["B4", "C4"])
        // A2被上一行第一个单元格合并
        table.rows.push(["B5", "C5"])                                            
        table.rows.push(["A6", "B6", "C6"])
        LogStatus('`' + JSON.stringify(table) + '`')
    }
    
    import json
    def main():
        table = {
            "type" : "table", 
            "title" : "表格演示", 
            "cols" : ["列A", "列B", "列C"], 
            "rows" : [
                ["A1", "B1", {"type": "button", "cmd": "coverAll", "name": "C1"}]
            ]
        }
        
        ticker = exchange.GetTicker()
        name = exchange.GetName()
        
        table["rows"].append([{"body": "A2 + B2:" + json.dumps(ticker), "colspan": 2}, "C2"])
        table["rows"].append([{"body": "A3 + A4 + A5:" + name, "rowspan": 3}, "B3", "C3"])
        table["rows"].append(["B4", "C4"])
        table["rows"].append(["B5", "C5"])
        table["rows"].append(["A6", "B6", "C6"])
        LogStatus("`" + json.dumps(table) + "`")
    
    void main() {
        json table = R"({
            "type" : "table", 
            "title" : "表格演示", 
            "cols" : ["列A", "列B", "列C"], 
            "rows" : [
                ["A1", "B1", {"type": "button", "cmd": "coverAll", "name": "C1"}]
            ]
        })"_json;
        // 为了测试,代码简短易读,这里使用构造的数据
        json jsonTicker = R"({"High": 0, "Low": 0, "Buy": 0, "Sell": 0, "Last": 0, "Time": 0, "Volume": 0})"_json;
        auto name = exchange.GetName();
        json arr1 = R"([{"body": "", "colspan": 2}, "C2"])"_json;
        arr1[0]["body"] = "A2 + B2:" + jsonTicker.dump();
        json arr2 = R"([{"body": "", "rowspan": 3}, "B3", "C3"])"_json;
        arr2[0]["body"] = "A3 + A4 + A5:" + name;
        table["rows"].push_back(arr1);
        table["rows"].push_back(arr2);
        table["rows"].push_back(R"(["B4", "C4"])"_json);
        table["rows"].push_back(R"(["B5", "C5"])"_json);
        table["rows"].push_back(R"(["A6", "B6", "C6"])"_json);
        LogStatus("`" + table.dump() + "`");
    }
    

状态栏表格分页显示:

function main() {
    var table1 = {type: 'table', title: 'table1', cols: ['列1', '列2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]}
    var table2 = {type: 'table', title: 'table2', cols: ['列1', '列2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]}
    LogStatus('`' + JSON.stringify([table1, table2]) + '`')
}
import json
def main():
    table1 = {"type": "table", "title": "table1", "cols": ["列1", "列2"], "rows": [ ["abc", "def"], ["ABC", "support color #ff0000"]]}
    table2 = {"type": "table", "title": "table2", "cols": ["列1", "列2"], "rows": [ ["abc", "def"], ["ABC", "support color #ff0000"]]}
    LogStatus("`" + json.dumps([table1, table2]) + "`")
void main() {
    json table1 = R"({"type": "table", "title": "table1", "cols": ["列1", "列2"], "rows": [ ["abc", "def"], ["ABC", "support color #ff0000"]]})"_json;
    json table2 = R"({"type": "table", "title": "table2", "cols": ["列1", "列2"], "rows": [ ["abc", "def"], ["ABC", "support color #ff0000"]]})"_json;
    json arr = R"([])"_json;
    arr.push_back(table1);
    arr.push_back(table2);
    LogStatus("`" + arr.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(["A", "B", "C"])
    tab3.rows.push(["A", "B", "C"])

    LogStatus('`' + JSON.stringify(tab1) + '`\n' + 
        '`' + JSON.stringify(tab2) + '`\n' +
        '`' + JSON.stringify(tab3) + '`')
  
    Log("exit")
}
import json
def main():
    tab1 = {
        "type": "table", 
        "title": "表格1", 
        "cols": ["1", "2"], 
        "rows": []
    }
    tab2 = {
        "type": "table", 
        "title": "表格2", 
        "cols": ["1", "2", "3"], 
        "rows": []
    }
    tab3 = {
        "type": "table", 
        "title": "表格3", 
        "cols": ["A", "B", "C"], 
        "rows": []
    }

    tab1["rows"].append(["jack", "lucy"])
    tab2["rows"].append(["A", "B", "C"])
    tab3["rows"].append(["A", "B", "C"])
    LogStatus("`" + json.dumps(tab1) + "`\n" + 
        "`" + json.dumps(tab2) + "`\n" + 
        "`" + json.dumps(tab3) + "`")
void main() {
    json tab1 = R"({
        "type": "table", 
        "title": "表格1", 
        "cols": ["1", "2"], 
        "rows": []
    })"_json;
    json tab2 = R"({
        "type": "table", 
        "title": "表格2", 
        "cols": ["1", "2", "3"], 
        "rows": []
    })"_json;
    json tab3 = R"({
        "type": "table", 
        "title": "表格3", 
        "cols": ["A", "B", "C"], 
        "rows": []
    })"_json;
    tab1["rows"].push_back(R"(["jack", "lucy"])"_json);
    tab2["rows"].push_back(R"(["A", "B", "C"])"_json);
    tab3["rows"].push_back(R"(["A", "B", "C"])"_json);
    LogStatus("`" + tab1.dump() + "`\n" + 
        "`" + tab2.dump() + "`\n" +
        "`" + tab3.dump() + "`");
}

运行效果:

注意: 策略实盘运行时,在实盘页面如果翻看历史记录,状态栏会进入休眠状态,停止更新。只有日志在第一页的时候状态栏数据才会刷新。 支持在状态栏输出base64编码后的图片,也支持在状态栏显示的表格中输出base64编码后的图片。由于编码后的图片的字符串数据一般很长,所以不再展示范例代码。

EnableLog()

EnableLog(IsEnable),打开或者关闭订单信息的日志记录。参数值:isEnable为布尔类型。IsEnable设置为false则不打印订单日志,不写入实盘数据库。

Chart(…)

Chart(...),自定义图表画图函数。

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

注意: 如果设置__isStock属性为false,即使用的图表为:Highcharts,如图所示:

Highcharts图表

如果设置__isStock属性为true,即使用的图表为:Highstocks(默认__isStocktrue),如图所示:

Highstocks图表

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

可以调用add(n, data, i)i为此数据在series中的索引)来更改对应的series中的数据。

可以为负数,-1指最后一个,-2是倒数第二个,例如画线时,修改线的最后一个点上的数据:

chart.add(0, [1574993606000, 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的数据。

HighStockshttp://api.highcharts.com/highstock

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

例如图表配置对象:

var cfgA = {
    extension: {
        // 不参于分组,单独显示,默认为分组 'group'
        layout: 'single', 
        // 指定高度,可以设置为字符串,"300px",设置数值300会自动替换为"300px"
        height: 300,      
        // 指定宽度占的单元值,总值为12
        col: 8            
    },
    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',
        // 指定初始数据后不需要用add函数更新,直接更改图表配置就可以更新序列
        data: [                    
            ["A", 25],
            ["B", 25],
            ["C", 25],
            ["D", 25]
        ]                
    }]
}

var cfgD = {
    extension: {
        layout: 'single',
        // 指定宽度占的单元值,总值为12
        col: 8,                    
        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", 
        "height" : 300,
        "col" : 8
    }, 
    "title" : {
        "text" : "盘口图表"
    },
    "xAxis" : {
        "type" : "datetime" 
    }, 
    "series" : [{
        "name" : "买一",
        "data" : []
    }, {
        "name" : "卖一", 
        "data" : []
    }]
}    

cfgB = {
    "title" : {
        "text" : "差价图"
    }, 
    "xAxis" : {
        "type" : "datetime"
    }, 
    "series" : [{
        "name" : "差价", 
        "type" : "column", 
        "data" : []
    }]
}    

cfgC = {
    "__isStock" : False,
    "title" : {
        "text" : "饼图"
    }, 
    "series" : [{
        "type" : "pie", 
        "name" : "one", 
        "data" : [
            ["A", 25],
            ["B", 25],
            ["C", 25],
            ["D", 25]
        ]
    }]
}    

cfgD = {
    "extension" : {
        "layout" : "single",
        "col" : 8,
        "height" : "300px"
    }, 
    "title" : {
        "text" : "盘口图表"
    }, 
    "series" : [{
        "name" : "买一", 
        "data" : []
    }, {
        "name" : "卖一",
        "data" : []
    }]
}    

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]
        ]
    }]
}
json cfgA = R"({
    "extension" : {
        "layout" : "single", 
        "height" : 300,
        "col" : 8
    }, 
    "title" : {
        "text" : "盘口图表"
    },
    "xAxis" : {
        "type" : "datetime" 
    }, 
    "series" : [{
        "name" : "买一",
        "data" : []
    }, {
        "name" : "卖一", 
        "data" : []
    }]
})"_json;    

json cfgB = R"({
    "title" : {
        "text" : "差价图"
    }, 
    "xAxis" : {
        "type" : "datetime"
    }, 
    "series" : [{
        "name" : "差价", 
        "type" : "column", 
        "data" : []
    }]
})"_json;    

json cfgC = R"({
    "__isStock" : false,
    "title" : {
        "text" : "饼图"
    }, 
    "series" : [{
        "type" : "pie", 
        "name" : "one", 
        "data" : [
            ["A", 25],
            ["B", 25],
            ["C", 25],
            ["D", 25]
        ]
    }]
})"_json;    

json cfgD = R"({
    "extension" : {
        "layout" : "single",
        "col" : 8,
        "height" : "300px"
    }, 
    "title" : {
        "text" : "盘口图表"
    }, 
    "series" : [{
        "name" : "买一", 
        "data" : []
    }, {
        "name" : "卖一",
        "data" : []
    }]
})"_json;    

json cfgE = R"({
    "__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]
        ]
    }]
})"_json;
  • cfgA.extension.layout属性

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

  • cfgA.extension.height属性

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

  • cfgA.extension.col属性

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

    运行完整范例策略:

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

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

    例如范例中,JavaScript范例部分代码段(完整范例):

    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方法更新数据,例如给饼图增加一个项目,JavaScript范例部分代码段(完整范例):

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

    简单的画图例子:

    // 这个chart在JavaScript语言中是对象,在使用Chart函数之前我们需要声明一个配置图表的对象变量chart
    var chart = {                                           
        // 该字段标记图表是否为一般图表,有兴趣的可以改成false运行看看
        __isStock: true,                                    
        // 缩放工具
        tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},    
        // 标题
        title : { text : '差价分析图'},                       
        // 选择范围
        rangeSelector: {                                    
            buttons:  [{type: 'hour',count: 1, text: '1h'}, {typ

More

qq89520 有一个问题_C函数是一直重试还是只重试一次

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

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

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

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

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

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

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

ethanwu 有本地调试工具吗?

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

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

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

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

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

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

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

宁公子 这个新字体好看~

hippo 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有没有微信群之类的?感谢

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

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

yhfgg python用的什么版本?

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

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

yhfgg 求python文档

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

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

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

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

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

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

我的昵称 这个 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 感觉这个平台棒棒哒,多在群里交流哈

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

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

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

btcrobot hi, world

小小梦 _C 函数会无脑重试,直到成功获取结果。

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

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

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

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

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

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

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

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

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

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

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

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地址。

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

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看能满足不能, 不能就只能找第三方库复制进策略了. 为了编译速度, 系统只内置了一些少量的库.

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

jiebang 谢谢

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

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

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

宁公子 exchange.GetRecords(PERIOD_D1);

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

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

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

momox 3q

Zero 暂时不能, 是隔离的.

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

Zero Javascript 资料网上到处都有哈

卖大 你的问题解决了吗?

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