在量化平台上的自动交易机器人不仅要有敏锐的洞察力,迅捷的执行速度,高效稳定的逻辑架构,当然也少不了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);
}
}
![](/uploads/allimg/220409/00061645a-0.jpg)
只用几行代码调用该 UI模版的 函数就可以 在BotVS的量化策略程序 上画出表格形式的UI显示,方便开发者根据数据、变量、状态显示的需求灵活设定,写出简洁的界面,另外还可以在UI上设置按钮,绑定相应的触发函数,来执行一些任务,可以更加灵活的与策略进行交互,操作,非常方便!数字货币 用户的UI设计
![](/uploads/allimg/220409/0006163431-1.jpg)
如有BUG 或者 建议 欢迎留言 ^^由 发明者量化(FMZ.COM) 授权首发刊载
学会麻将怎么打?,其次,还要掌握相关的游戏技巧。像是搬庄决定游戏公平,决定出牌顺序,决定谁是第一位庄家;还有位置不能够轻易改变,以保证游戏的公平性;游戏过程中不能够总是停顿,避免出现其他的问题等等。
麻将绝技二、打麻将的时候要尽可能的保证自己手里有两个花色,尽量凑齐两种花色,这样扣听的概率会大大提高。相同的道理,如果看到其他三家总是再打哪种花色大概我们也就能猜出你需要的是什么花色。比如说总是打萬的话可能就是再凑萬真人棋牌游戏,把萬凑成一幅,这样的时候上家就要小心,不要打萬,自己预算一下看看是什么情况,尽量不要给下家吃牌的机会。