PriceDiff), Precision); // 开仓平仓价差,即 每个节点的盈利空间 var state = fishTable[idx]; // 赋值 渔网 节点的状态 var fishId = uuidTable[idx]; // 编号
// 此处判断作用为: 过滤 未完成的订单
if (hasOrder(orders, fishId)) { // 如果 所有未完成订单,即挂单数组 中有ID为 fishId 的订单
continue; // 跳过本次循环 继续循环
}
if (fishId != -1 && IsSupportGetOrder) { // 网格 节点 id 不等于 初始值,即下过订单,并且 交易所支持 GetOrder
var order = trader.GetOrder(fishId); // 获取 该 fishId 号 的订单
// 此处判断作用为: 过滤 没有找到订单 的 网格节点,以下判断(state == STATE_WAIT_COVER) 等等 的逻辑不会触发
if (!order) { // 如果 !order 为真 即获取订单失败
Log("获取订单信息失败, ID: ", fishId); // 输出日志
continue; // 跳过本次循环 继续循环
}
// 此处判断作用为: 过滤 处于挂起状态,未成交,或者 未完全成交的 网格节点, 以下判断(state == STATE_WAIT_COVER) 等等 的逻辑不会触发
if (order.Status == ORDER_STATE_PENDING) { // 如果订单状态 是在交易所 挂起状态
//Log("订单状态为未完成, ID: ", fishId);
continue; // 跳过本次循环 继续循环
}
}
if (state == STATE_WAIT_COVER) { // 如果 当前节点 状态是 等待平仓
var coverId = CoverFunc(coverPrice, (BuyFirst ? amountS[idx] : amountB[idx]), (BuyFirst ? '完成买单:' : '完成卖单:'), openPrice, '量:', (BuyFirst ? amountB[idx] : amountS[idx]));
// 调用 平仓 函数 CoverFunc 挂出 平仓单
if (typeof(coverId) === 'number' || typeof(coverId) === 'string') { // 判断 如果 平仓函数 返回的 Id 为 数值(由 发明者量化 API 直接返回) 或者 字符串(由 trader 对象的 Buy/Sell函数返回)
fishTable[idx] = STATE_WAIT_CLOSE; // 已经挂出 平仓单, 更新状态为 : STATE_WAIT_CLOSE 即等待 节点任务完成
uuidTable[idx] = coverId; // 把 订单号 储存在 uuidTable 对应的 idx 位置上。
}
} else if (state == STATE_WAIT_OPEN || state == STATE_WAIT_CLOSE) { // 如果状态是 等待开仓 或者 等待完成
var openId = OpenFunc(openPrice, BuyFirst ? amountB[idx] : amountS[idx]); // 下开仓单。
if (typeof(openId) === 'number' || typeof(openId) === 'string') { // 判断是否下单成功
fishTable[idx] = STATE_WAIT_COVER; // 更新状态 为等待平仓
uuidTable[idx] = openId; // 记录当前 节点 订单ID
if (state == STATE_WAIT_CLOSE) { // 如果是等待完成 (开仓订单下了后 才会触发)
ProfitCount++; // 累计盈利次数
var account = _C(exchange.GetAccount); // 获取当前账户信息
var ticker = _C(exchange.GetTicker); // 获取当前行情信息
var initNet = _N(((InitAccount.Stocks + InitAccount.FrozenStocks) * ticker.Buy) + InitAccount.Balance + InitAccount.FrozenBalance, 8);
// 计算 初始 资产 净值
var nowNet = _N(((account.Stocks + account.FrozenStocks) * ticker.Buy) + account.Balance + account.FrozenBalance, 8);
// 计算 当前 资产 净值
var actualProfit = _N(((nowNet - initNet)) * 100 / initNet, 8); // 计算 收益率
if (AmountType == 0) { // 根据 买卖同量 , 自定义量 不同的处理。
var profit = _N((ProfitCount * amount * PriceDiff) + LastProfit, 8); // 计算: 所有盈利节点的 盈亏 和 上次撒网盈亏 之和 即 总盈亏
Log((BuyFirst ? '完成卖单:' : '完成买单:'), coverPrice, '量:', (BuyFirst ? amountS[idx] : amountB[idx]), '平仓收益', profit);
// 输出 订单完成信息
} else {
Log((BuyFirst ? '完成卖单:' : '完成买单:'), coverPrice, '量:', (BuyFirst ? amountS[idx] : amountB[idx]));
}
}
}
}
}
Sleep(CheckInterval); // 网格逻辑 主要 while 循环检测, 每次 暂停一定时间 CheckInterval 即:检测间隔
}
return true; // 本次撒网完成 返回 true
}
function main() { // 策略主函数,程序从这里开始执行。 if (ResetData) { // RestData 为界面参数, 默认 true , 控制 启动时 是否清空所有数据。默认全部清空。 LogProfitReset(); // 执行 API LogProfitReset 函数,清空 所有收益。 LogReset(); // 执行 API LogReset 函数, 清空 所有日志。 } // exchange.SetMaxDigits(Precision) // 已废弃,使用 exchange.SetPrecision 代替。 exchange.SetPrecision(Precision, 3) // exchange.SetPrecision(2, 3); // 设置价格小数位精度为2位, 品种下单量小数位精度为3位 // Precision 为界面参数。
if (typeof(AmountType) === 'undefined') { // 订单 数量类型, 0:“买卖同量” , 1:“自定义量” , 检测 如果该参数是 未定义的,默认设置 0 。
AmountType = 0; // typeof 会 检测 AmountType 的类型, 如果是 undefined 即 “未定义” ,则给 AmountType 赋值 0。
}
if (typeof(AmountDot) === 'undefined') { // 订单量 小数点 最长位数 AmountDot 如果是 未定义的, 设置 AmountDot 为 3 。
AmountDot = 3; // 其实已经由 exchange.SetPrecision(Precision, 3) 设置过了,在底层会截断处理。
}
if (typeof(EnableDynamic) === 'undefined') { // 检测 是否 开启动态挂单 参数, 如果 EnableDynamic 是未定义的, 设置 为 false 即 不开启。
EnableDynamic = false;
}
if (typeof(AmountCoefficient) === 'undefined') { // 如果未定义, 默认设置 "*1"
AmountCoefficient = "*1";
}
if (typeof(EnableAccountCheck) === 'undefined') {// 如果未定义, 启用资金检验 参数 设置为 true ,即 开启。
EnableAccountCheck = true;
}
BuyFirst = (OpType == 0); // 根据 OpType 的设置 去 给BuyFirst 赋值, OpType 设置网格类型, 0: 先买后卖, 1: 先卖后买
IsSupportGetOrder = exchange.GetName().indexOf('itstamp') == -1; // 检测 交易所 名称, 如果是 Bitstamp 则提醒
if (!IsSupportGetOrder) {
Log(exchange.GetName(), "不支持GetOrder, 可能影响策略稳定性.");
}
SetErrorFilter("502:|503:|S_U_001|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|refused|EOF|When");
// SetErrorFilter 过滤错误信息
exchange.SetRate(1);
Log('已经禁用汇率转换, 当前货币为', exchange.GetBaseCurrency()); // 禁用汇率转换
if (!RestoreProfit) { // 恢复上次盈利 若果是 false 则 给 LastProfit 赋值 0 , 即不恢复。
LastProfit = 0;
}
var orgAccount = _C(exchange.GetAccount); // 获取账户信息, 此处记录 策略开始运行时的 初始账户信息 ,用于 计算一些收益,如: 总体浮动盈亏 等。本策略有几个参数 都是 该变量传入。
var fishCount = 1; // 撒网次数 初始1
while (true) { // 策略 主循环
if (!fishing(orgAccount, fishCount)) { // 撒网函数 fishing
break;
}
fishCount++; // 撒网次数 累计
Log("第", fishCount, "次重新撒网..."); // 输出 撒网信息。
FirstPriceAuto = true; // 重置 首价格自动 为true
Sleep(1000); // 轮询间隔 1000毫秒
}
}
### 如有注释错误,欢迎指正 ^^
活着 可以留个联系方式吗,大佬
活着 这个策略可以设置有利位置最大边界自动移动,如果是不利位置可以移动吗,还是只能靠止损重新撒网,但是重新撒网好像平衡有问题,无法平衡到策略初始状态。我平衡了几次都是币不足只能创建两三格网格。
18180828122 不支持合约吗,回测合约提示订阅失败
kkms mark
jjkk 当网格比较多的时候,下单超过api调用频率了,在什么地方加个延时呀??
逍遥侯CC 楼主能留个联系方式吗
nxtplayer 666,学习一下代码思路
发明者量化-小小梦 V : DoMyBestForeverAgo
发明者量化-小小梦 这个策略应该是个现货策略。
jjkk 具体在什么地方呀,找不到呀
发明者量化-小小梦 控制下 轮询 间隔时间 或者 , 下单 时候的 间隔时间。
发明者量化-小小梦 BotVS QQ群 可以QQ我 ^^ : 小小梦