在量化平台上的自动交易机器人不仅要有敏锐的洞察力,迅捷的执行速度,高效稳定的逻辑架构,当然也少不了UI界面。说起UI界面并不是要非常的炫酷,特效华丽,这方面是BotVS不太擅长的。但是简洁、灵活、直观、便捷的UI界面一直是BotVS的追求!
下面我们可以一起来学习一个可复用的UI模版。
感谢平台用户 ID :职业养鸡户 共享该模版:
该模版使用比较简单,每个函数的作用都有说明,在开发策略的时候可以更好的架构策略,分离出显示界面。
提取、修改、更新状态栏数据也变得比较容易,非常方便,而且代码量很小,也比较适合扩展。有兴趣的用户可以学习一下源码,这里逐行翻译了一下。
方便了解这个模版的运行细节。
main 函数 测试部分 可以复制到单独的策略,然后引用该模版测试。
/*
作者: ID 养鸡专业户
翻译: littleDream
*/
var listener = Array(); // 声明一个 全局变量 并且初始化为空数组对象, 用来储存 按钮(button)响应的 函数引用。
// 用于构造 按键 对象的函数
TableButton = function(cmd, name, callback) { // cmd : 用于 GetCommand 捕获的 命令 , name : 按键显示的名称 修改:增加 callback
var self = {} // 构造一个 空对象
self.type = "button"; // 给构造的对象 添加 属性 type 并 赋值 "button" , 参见 API 文档 LogStatus 函数,和论坛帖子“策略状态栏中构造交互按钮功能”
self.cmd = cmd; // 添加 cmd 属性 并用参数 cmd 赋值
self.name = name; // 添加 name 属性
// 下行新增
listener[cmd] = callback; // 给对应的 命令通过 键--键值 绑定 对应的回调函数
return self; // 返回构造好的对象
}
// 模版导出函数, 用于设置 表格信息,返回一个对象可以调用 该对象的成员函数压入 数据
$.TableInfo = function() {
var self = {} // 构造一个 空对象
self.cols = []; // 给构造的空对象 添加属性 cols 并赋值 一个 空数组
self.rows = []; // 给构造的空对象 添加属性 rows 并赋值 一个 空数组
self.pushBtn = function(col, cmd, name, callback) { // 添加 属性 pushBtn 引用一个 匿名函数, 参数为 列名、捕获的命令、按钮名称、回调函数(按钮最终触发的函数)
/* var btn = TableButton(cmd, name) */
self.cols.push(col) // 向列 压入数据 显示为列名
self.rows.push({ // 压入 按钮的 格式(JSON)
'type': 'button', // 类型设置 为 按钮
'cmd': cmd, // 触发的 命令
'name': name // 按钮上显示的名称
})
listener[cmd] = callback; // 给对应的 命令通过 键--键值 绑定 对应的回调函数
}
self.push = function(col, row) { // 压入 普通数据 参数 : col 列名, row : 行上的值
self.cols.push(col) // 压入 数组 操作
self.rows.push(row) // 压入 数组 操作
}
return self; // 返回构造的对象
}
// 构造 table 表格对象, createTable 表格对象的构造函数
function createTable() {
var self = {} // 声明一个 空对象
self.type = "table" // 添加属性 type , 用 “table” 赋值, 定义表格类型用于在状态栏显示 出表格,参见API文档 LogStatus 函数
self.title = "持仓信息" // 表格显示的 分页标题 默认 为 “持仓信息”
self.cols = [] // 用以储存表格的列名
self.rows = [] // 用以储存表格的行数据
// 声明的空对象添加成员函数
self.SetRowByTableInfo = function(index, argument) { // 根据 导出函数 $.TableInfo 返回的对象 去设置 表格的 row 行数据,参数是: 行号,$.TableInfo的返回值
if (argument.cols != null) // 传入的参数 argument.cols 不等于 null
self.cols = argument.cols; // 替换掉 列名
self.rows[index] = argument.rows; // 替换掉 指定 行数 index 的行数据 rows
}
self.SetRow = function(index, rowself) { // 设置行数据,直接设置, 参数 设置的行 index , 要设置的数据rowself
while (self.rows.length < index) // 如果超出 先添加 空白行 , 应该是 -1 if 修改为 while , 添加之间的空行。
self.rows.push(Array(rowself.length)) // self.push("") 修改
self.rows[index] = rowself // 参数 传入的行数据 rowself 赋值给 表格数组中 指定的行的索引位置
}
self.SetRowCount = function(count) { // 设置行数, 传入的参数就是 需要设置的 行数。
// 增加代码
var lengthOfcols = self.cols.length;
while (self.rows.length < count) { // 这里使用一个循环 来 把当前 不足的行数 补充一下。
self.rows.push(Array(lengthOfcols)); // 只要当前的行数 即:self.rows.length 小于 参数 count , 就向 self.rows push 空 ""
}
if (self.rows.length > count) { // 如果 参数 count 小于当前的 已有行数。
self.rows.splice(count, self.rows.length - count) // 调用数组的 元素删除函数 splice 删除 索引count 开始 (self.rows.length - count) 个 元素,即:删除 多于的元素。
}
}
self.GetRow = function(index) { // 获取 指定行数的 表格行数据。
return self.rows[index]
}
self.Init = function(title/*, cols, rows*/) { // 初始化表格 , 参数 : 分页标题
self.title = title; // 表格 对象的 title 属性 设置为 参数传入的 字符串
/*作者删除
if (cols != null) // 如果传入的 cols 不为 null, 把参数cols 赋值给 表格对象的 cols 属性
self.cols = cols;
if (rows != null) { // 如果传入的 rows 不为 null, 对 参数 rows 遍历处理,压入编号
// 此处应该有一个判断 rows 是否是数组。
for (var i = 0; i < rows.length; i++) { // 遍历
self.rows.push(rows[i]); // 修改 rows.push("r" + i)
}
}
*/
}
return self; // 返回 表格对象
}
$.createTableMgr = function() { // 构造表格控制对象
var self = {} // 声明一个 空对象
self.table = [] // 声明一个 空数组, table 感觉 tabls 贴切, 这个table 变量用来存放 表格对象,可以同时显示出多个表格。
self.GetTable = function(index) { // 给表格控制对象添加 成员函数: 获取表格 GetTable , 参数 index 指定获取 哪个表格。
if (typeof(index) === 'number') { // 如果传入的 参数 index 为数值类型 , 返回索引为 index 的 self.table 数组的元素。
return self.table[index] // 如果索引 index 输入 超出, 还是有可能返回 undefined
} else {
for (var i = 0; i < self.table.length; i++) { // 如果传入的 参数 index 不是索引,而是 表格对象的 分页标题 字符串, 则遍历 self.table 数组
if (self.table[i].title == index) // 对比每一个 表格对象的 分页标题, 找到相同的 分页标题 就返回该 表格对象。
return self.table[i] // 返回 表格对象
}
}
}
self.AddTable = function(title, cols, rows) { // 把 表格对象 添加到 表格控制对象的 table 属性。 可以指定 表格的标题 ,列数据 , 行数据
var tb = createTable(); // 调用 createTable 函数 构造一个 表格对象 赋值给 tb
tb.Init(title, cols, rows); // 调用 表格对象的 成员函数 初始化表格 传入参数 title, cols, rows
self.table.push(tb) // 把构造好的 表格对象压入 表格控制对象 的属性 table 数组中。
return tb; // 返回这个 添加 的表格对象。
}
/* 作者删除
self.AddListener = function(key, value) { // 添加 监听函数。
self.listener[key] = value; // 此处测试。
}
*/
self.UpdateCMD = function() { // 检测按钮 触发 命令。
var cmd = GetCommand() // 调用 API 函数 检测 交互有没有触发
if (cmd) { // 如果 cmd 接受到交互信息
var cmdstr = cmd + ""; // 用空字符串 加 cmd 做转换为字符串, 应该可以直接 用cmd
if (!!listener[cmdstr]) { // !!listener[cmdstr] 表达式 返回 false 即 listener 中没有 cmdstr 为 键的值, 如果 为true 则是有值(即:cmdstr 命令对应的回调函数)
listener[cmdstr](cmdstr); // 调用 该命令对应的回调函数 。
} else {
Log("找不到名为:" + cmdstr + "的命令") // 否则 打印日志 : 找不到 命令
}
}
}
self.LogStatus = function(before, end) { // 表格控制对象 添加的 成员函数 LogStatus (即 封装一下 API LogStatus)
self.UpdateCMD(); // 检测交互命令 , 调用 表格控制对象的成员函数 UpdateCMD 。 如果有 按钮按下 ,就会触发相应 命令的 回调函数(在listener 中 Key-value形式储存)
LogStatus(before + '\n`' + JSON.stringify(self.table) + '`\n' + end); // 支持多个表格同时显示, 将以TAB显示到一组里, 把参数 before ,end 添加在显示的表格 前、后, 调用API LogStatus
// 显示表格到状态栏。 要显示的表格都储存在 self.table 这个数组中, 详细的API 参见 文档: https://www.botvs.com/api 全局函数 LogStatus 函数
}
return self;
}
function main() {
// 测试 表格控制对象
var tb_manager = $.createTableMgr();
var tb1 = tb_manager.AddTable("ceshi1");
var tb2 = tb_manager.AddTable("ceshi2");
var tb3 = tb_manager.AddTable("ceshi3");
tb_manager.LogStatus("up", "down");
// 测试 GetTable 函数
var obj_tb2 = tb_manager.GetTable("ceshi2");
Log("obj_tb2:", obj_tb2);
// 测试 $.TableInfo
var info1 = $.TableInfo();
for(var i = 0; i < 5; i++){
info1.push("" + i, "a" + i);
}
tb1.SetRowByTableInfo(0, info1);
// 测试 SetRow 函数
tb1.SetRow(3, ["a", "b", "d"]); // 超出已有索引 ,会再之前插入空行
tb_manager.LogStatus("up", "down");
// 测试 SetRowCount
var info2 = $.TableInfo();
info2.push("name", "Tom");
info2.push("age", 12);
tb2.SetRowByTableInfo(0, info2);
tb2.SetRowCount(6);
tb_manager.LogStatus("up", "down");
// 测试GetRow
var tb2_row = tb2.GetRow(0);
Log("tb2_row:", tb2_row);
// 测试 TableButton
var info3 = $.TableInfo();
info3.push("按钮", TableButton("cover", "平仓", function(cmd){
var time = new Date().getTime();
Log(_D(time), "cmd:", cmd, "全平仓!#FF0000");
}));
tb3.SetRowByTableInfo(0, info3);
tb_manager.LogStatus("up", "down");
// 实盘测试 循环 避免程序 结束, 把 main 函数 复制到 单独的 策略中进行实际测试。
while(true){
// 测试 UpdateCMD
var nowTime = new Date().getTime();
tb_manager.UpdateCMD();
tb_manager.LogStatus("time:" + _D(nowTime), "down");
Sleep(1000);
}
}
只用几行代码调用该 UI模版的 函数就可以 在BotVS的量化策略程序 上画出表格形式的UI显示,方便开发者根据数据、变量、状态显示的需求灵活设定,写出简洁的界面,另外还可以在UI上设置按钮,绑定相应的触发函数,来执行一些任务,可以更加灵活的与策略进行交互,操作,非常方便!
数字货币 用户的UI设计
如有BUG 或者 建议 欢迎留言 ^^
由 发明者量化(FMZ.COM) 授权首发刊载
2充钻方法:打开客户端,充钻第一步:官方规定有两个渠道,第一找V群主,第二加官方客服服V:pipi696929,随便一种方法即可完成充钻,充钻第二步:充钻前发送一下截图或者发送箭头所指处的ID号码,发送到充钻人员处,即可完成整个充钻。