평일에는 기획을 하는 것이 즐거워하고, 편집기에는 다양한 무작위적인 아이디어가 쏟아져 나오고, 아마도 당신의 다음
신한 잔이 될지도 모르죠. 이 열정을 좌지우지하는 유일한 것은 거래 전략 시스템에서 구매 및 판매 논리를 처리하는 것입니다. 이 거래 모듈의 처리도 매우 중요하지만 다소 지루하고 논리가 복잡합니다.
/* Interval 실패 재시험 간격 (millisecond) 숫자 (number) 500 SlideTick 슬라이드 가격 점수 (진수) 숫자 형식 (수) 1 RiskControl 바람 제어 가동 불형 ((true/false) false MaxTrade@RiskControl 일일 최대 거래 거래 횟수 숫자 형식 (number) 50 MaxTradeAmount@RiskControl 한 장 최대 한 장의 자금 수 숫자형 (number) 1000 */
var __orderCount = 0 // 현재 일일에 다음 단위를 기록합니다 var __orderDay = 0 // 현재 작업일 날짜를 기록합니다
function CanTrade ((tradeAmount) { // 위험 제어 모듈, 매개 변수: 거래 수
if (!RiskControl) { // 기본 설정으로는 풍경 제어 모듈을 열지 않습니다. 열지 않으면 CanTrade 함수가 true를 반환합니다.
true를 반환합니다
♪ ♪
if (typeof(tradeAmount) ==
function init ((() { // 템플릿 초기화 함수, 템플릿 로딩 시 먼저 이 함수를 실행한다.
if (typeof(SlideTick) ===
function GetPosition ((e, contractType, direction, positions) { // 거래소 개체, 계약 유형, 방향, API 반환된 보유 데이터 ((空可) 와 같은 방향의 계약의 어제 포지션 현재 포지션을 결합합니다.
var allCost = 0; // contractType 계약 방향 총 지출 금액, 1인당 계약의 몇 점으로 곱하지 않습니다 ( 전체로 계약할 수 있기 때문에)
var allAmount = 0; // 총 계약 수
var allProfit = 0; // 이익과 손실의 총
var allFrozen = 0; // 전체 얼음 수
var pos 마진 = 0; // 보유 계약 레버리지
if (typeof(positions) ===
function Open ((e, contractType, direction, opAmount) { // 동작 단일 품종 계약의 오픈 거래 함수, 매개 변수: 거래소 대상, 계약 코드, 방향, 동작 수
var initPosition = GetPosition ((e, contractType, direction); // 위쪽의 GetPosition 함수를 호출하여 결합된 저장 정보를 얻는다.
var isFirst = true; // isFirst를 설정합니다.
var initAmount = initPosition? initPosition.Amount : 0; // initPosition가 null이라면 initAmount가 0을 부여하고 그렇지 않으면 initPosition.Amount가 0을 부여한다.
var positionNow = initPosition; // 변수 positionNow가 현재 저장된 정보를 표시한다고 선언합니다
while (true) { // while 루킹
var needOpen = opAmount; // 임시 변수 needOpen을 선언하고 변수에 대 한 값을 부여 합니다.
if (isFirst) { // 처음 실행되면 isFirst만 업데이트합니다. if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (isFirst) { // if (if (isFirst) { // if (if
isFirst = false;
} else {
positionNow = GetPosition ((e, contractType, direction); // 현재 보유 정보를 업데이트합니다.
if (positionNow) { // 포지션 정보가 있다면 다음 포지션 개척이 필요한 숫자 needOpen은 파라미터 요구되는 작업의 양과 같습니다.
needOpen = opAmount - (positionNow.Amount - initAmount);
♪ ♪
♪ ♪
var insDetail = _C ((e.SetContractType, contractType); // 계약 유형을 설정하십시오.
// Log ((
function Cover ((e, contractType) { // 단일 품종 평행함수, 매개 변수: 거래소 객체, 계약 코드
var insDetail = _C ((e.SetContractType, contractType); // 계약 유형을 설정
while (true) { // 주 순환 while
var n = 0; // 평면 작업 계산
var opAmount = 0; // 선언 동작 변수
var positions = _C ((e.GetPosition); // API 호출 취득 보관 정보, 위의 구별 취득 보관 함수. 자세한 내용은 API 문서를 참조하십시오.
for (var i = 0; i < positions.length; i++) { // 탐색 저장 정보
if (positions[i].ContractType!= contractType) { // 만약 현재 인덱스의 보유 정보가 계약이 동작하는 계약과 같지 않다면: contractType
Continue; // 건너뛰기
♪ ♪
var amount = Math.min ((insDetail.MaxLimitOrderVolume, positions[i].Amount); // 통보의 최대 거래량을 제어하지 않습니다
var depth;
if (positions[i].Type == PD_LONG の の positions[i].Type == PD_LONG_YD) { // 다중 포즈를 처리
depth = _C ((e.GetDepth); // API를 호출하여 현재 인프라 데이터를 얻는다
opAmount = Math.min ((amount, depth.Bids[0].Amount); // 제한 작업 크기는 디스크 한 대보다 크지 않습니다.
if (!CanTrade ((opAmount)) { // 바람 제어 모듈 검출
e.Sell(depth.Bids[0].Price - (insDetail.PriceTick * SlideTick), opAmount, contractType, positions[i].Type == PD_LONG ? "平今" : "平昨", 'Bid', depth.Bids[0]);
// 执行平仓 API ,详细参见 API文档。
n++; // 操作计数累加
} else if (positions[i].Type == PD_SHORT || positions[i].Type == PD_SHORT_YD) { // 处理 空仓 类似多仓处理
depth = _C(e.GetDepth);
opAmount = Math.min(amount, depth.Asks[0].Amount);
if (!CanTrade(opAmount)) {
return;
}
e.SetDirection(positions[i].Type == PD_SHORT ? "closesell_today" : "closesell");
e.Buy(depth.Asks[0].Price + (insDetail.PriceTick * SlideTick), opAmount, contractType, positions[i].Type == PD_SHORT ? "平今" : "平昨", 'Ask', depth.Asks[0]);
n++;
}
}
if (n === 0) { // 如果n 等于 0 ,即初始为0 ,在遍历时没有累加,没有可平的仓位。
break; // 跳出主while循环
}
while (true) { // 间隔一定时间后, 取消所有挂单。类似Open函数的 CancelPendingOrders
Sleep(Interval);
var orders = _C(e.GetOrders);
if (orders.length === 0) {
break;
}
for (var j = 0; j < orders.length; j++) {
e.CancelOrder(orders[j].Id);
if (j < (orders.length - 1)) {
Sleep(Interval);
}
}
}
}
}
var trans = { // 상태 탭에서 상세한 계정 정보를 표시하는 중국어 번역, 사전
function AccountToTable ((jsStr, title) { // 함수 함수는 계정 정보를 상태 탭 표로 내보내는 함수, 매개 변수: 표시하려는 JSON 구조 문자열, 제목
if (typeof(title) ===
var PositionManager = (function() { // 변수를 선언 PositionManager는 익명 함수의 반환 값을 받아서 생성된 객체로 반환합니다
function PositionManager ((e) { // PositionManager라는 함수가 익명 함수의 내부에 있다고 선언한다.
if (typeof(e) ===
PositionManager.prototype.GetPosition = function(contractType, direction, positions) { // 给 PositionManager 添加方法 用于在主策略中调用该模板的 函数
return GetPosition(this.e, contractType, direction, positions);
};
PositionManager.prototype.OpenLong = function(contractType, shares) { // 添加 开多仓 方法
if (!this.account) {
this.account = _C(this.e.GetAccount);
}
return Open(this.e, contractType, PD_LONG, shares);
};
PositionManager.prototype.OpenShort = function(contractType, shares) { // 添加 开空仓 方法
if (!this.account) {
this.account = _C(this.e.GetAccount);
}
return Open(this.e, contractType, PD_SHORT, shares);
};
PositionManager.prototype.Cover = function(contractType) { // 添加 平仓 方法
if (!this.account) {
this.account = _C(this.e.GetAccount);
}
return Cover(this.e, contractType);
};
PositionManager.prototype.CoverAll = function() { // 添加 所有仓位全平方法
if (!this.account) {
this.account = _C(this.e.GetAccount);
}
while (true) {
var positions = _C(this.e.GetPosition)
if (positions.length == 0) {
break
}
for (var i = 0; i < positions.length; i++) { // 首先平掉 对冲合约 对冲合约 举例 MA709&MA705
// Cover Hedge Position First
if (positions[i].ContractType.indexOf('&') != -1) {
Cover(this.e, positions[i].ContractType)
Sleep(1000)
}
}
for (var i = 0; i < positions.length; i++) {
if (positions[i].ContractType.indexOf('&') == -1) {
Cover(this.e, positions[i].ContractType)
Sleep(1000)
}
}
}
};
PositionManager.prototype.Profit = function(contractType) { // 添加计算收益的方法
var accountNow = _C(this.e.GetAccount);
return _N(accountNow.Balance - this.account.Balance);
};
return PositionManager; // 匿名函数返回 在自身内声明的 PositionManager 函数(对象)。
})();
$.NewPositionManager = function(e) { // 함수를 내보내 PositionManager 객체를 구성합니다 return new 위치 관리자 ((e); };
// 위키백과http://mt.sohu.com/20160429/n446860150.shtml$.IsTrading = function ((symbol) { // 계약이 거래 중인지 판단하는 시간장, 매개 변수 symbol 계약 코드 var now = new Date ((); // 현재 시간 객체를 가져옵니다 var day = now.getDay ((); // 현재 시간을 주 중 어느 특정 날에 얻는다. var hour = now.getHours ((); // 24시간 중 한 시간을 얻는다 var minute = now.getMinutes ((); //분 1분 중 어떤 분을 얻는가
if (day === 0 || (day === 6 && (hour > 2 || hour == 2 && minute > 30))) { // 第一个过滤, day == 0 星期天 或者 day == 6 星期六并且
return false; // 2点30以后 。 星期五 夜盘结束。 返回 false 即所有品种不在交易时间
}
symbol = symbol.replace('SPD ', '').replace('SP ', ''); // 正则表达式 匹配其交易系统用“SPD”表示跨期套利交易,若指令买进“SPD CF1609&CF17...
// 过滤掉 跨期套利的 合约编码
var p, i, shortName = "";
for (i = 0; i < symbol.length; i++) { // 遍历合约代码字符串,取出 代码(排除数字的部分)赋值给shortName 并且转换为大写
var ch = symbol.charCodeAt(i);
if (ch >= 48 && ch <= 57) {
break;
}
shortName += symbol[i].toUpperCase();
}
var period = [ // 通常交易时间 9:00 - 10:15,
[9, 0, 10, 15], // 10:30 - 11:30
[10, 30, 11, 30], // 13:30 - 15:00
[13, 30, 15, 0]
];
if (shortName === "IH" || shortName === "IF" || shortName === "IC") { // 如果是这些 品种,交易时间 period 调整
period = [
[9, 30, 11, 30],
[13, 0, 15, 0]
];
} else if (shortName === "TF" || shortName === "T") { // 国债品种 时间调整
period = [
[9, 15, 11, 30],
[13, 0, 15, 15]
];
}
if (day >= 1 && day <= 5) { // 如果是 周一 到周五, 不考虑夜盘。 判断当前时间是否符合 period 设定的时间表
for (i = 0; i < period.length; i++) {
p = period[i];
if ((hour > p[0] || (hour == p[0] && minute >= p[1])) && (hour < p[2] || (hour == p[2] && minute < p[3]))) {
return true; // 符合遍历出的 时间表 中的 时间段, 即该品种在交易时间内。
}
}
}
var nperiod = [ // 额外判断 夜盘品种 nperiod[n][0] 是夜盘时间相同的一类
// 品种汇总,nperiod[n][1] 就是该类品种的夜盘交易时间
[
['AU', 'AG'],
[21, 0, 02, 30]
],
[
['CU', 'AL', 'ZN', 'PB', 'SN', 'NI'],
[21, 0, 01, 0]
],
[
['RU', 'RB', 'HC', 'BU'],
[21, 0, 23, 0]
],
[
['P', 'J', 'M', 'Y', 'A', 'B', 'JM', 'I'],
[21, 0, 23, 30]
],
[
['SR', 'CF', 'RM', 'MA', 'TA', 'ZC', 'FG', 'IO'],
[21, 0, 23, 30]
],
];
for (i = 0; i < nperiod.length; i++) { // 遍历所有夜盘品种 交易时间段,对比当前时间。
for (var j = 0; j < nperiod[i][0].length; j++) {
if (nperiod[i][0][j] === shortName) {
p = nperiod[i][1];
var condA = hour > p[0] || (hour == p[0] && minute >= p[1]);
var condB = hour < p[2] || (hour == p[2] && minute < p[3]);
// in one day
if (p[2] >= p[0]) {
if ((day >= 1 && day <= 5) && condA && condB) {
return true;
}
} else {
if (((day >= 1 && day <= 5) && condA) || ((day >= 2 && day <= 6) && condB)) {
return true;
}
}
return false;
}
}
}
return false;
};
$.NewTaskQueue = function ((onTaskFinish) { // 다종류 트랜잭션을 수행하는 큐어 객체 구성 함수. 파라그램: 작업이 완료되면 호출 함수. var self = {} // 공허한 객체를 선언합니다 self.ERR_SUCCESS = 0 // 정의 반환 메시지 성공 self.ERR_SET_SYMBOL = 1 // 계약 설정 오류 self.ERR_GET_RECORDS = 2 // K줄을 얻는 오류 self.ERR_GET_ORDERS = 3 // 오더가 완료되지 않은 것을 얻었다 self.ERR_GET_POS = 4 // 저장 정보 획득 오류 self.ERR_TRADE = 5 // 거래 오류 self.ERR_GET_DEPTH = 6 // 깊이 파장을 얻는 오류 self.ERR_NOT_TRADING = 7 // 거래 시간에 없습니다 self.ERR_BUSY = 8 // 차단
self.onTaskFinish = typeof(onTaskFinish) === 'undefined' ? null : onTaskFinish // 如果在 初始化队列对象时没有 传入需要回调的匿名函数,该属性赋值为null,否则赋值回调函数
self.retryInterval = 300 // 重试间隔 毫秒数
self.tasks = [] // 这个是一个重要的属性,队列中储存任务的数组。
self.pushTask = function(e, symbol, action, amount, arg, onFinish) { // 给空对象添加函数,该函数是压入 新任务 到任务数组中。参数分别为:
// 交易所对象、合约代码、执行动作、数量、回调函数参数、回调函数
var task = { // 构造一个任务对象
e: e, // 交易所对象
action: action, // 执行的动作
symbol: symbol, // 合约代码
amount: amount, // 操作数量
init: false, // 是否初始化
finished: false, // 是否任务完成
dealAmount: 0, // 已处理的 量
preAmount: 0, // 上一次的 量
preCost: 0, // 上一次的 花费
retry: 0, // 重试次数
maxRetry: 10, // 最大重试次数
arg: typeof(onFinish) !== 'undefined' ? arg : undefined, // 如果没有传入 回调函数,此项 设置为 undefined
onFinish: typeof(onFinish) == 'undefined' ? arg : onFinish // 如果没有传入回调函数,把 arg 复制给 onFinish(实际上是 arg没传入,中间隔过去了)
}
switch (task.action) { // 根据执行的动作初始化描述信息
case "buy":
task.desc = task.symbol + " 开多仓, 数量 " + task.amount
break
case "sell":
task.desc = task.symbol + " 开空仓, 数量 " + task.amount
break
case "closebuy":
task.desc = task.symbol + " 平多仓, 数量 " + task.amount
break
case "closesell":
task.desc = task.symbol + " 平空仓, 数量 " + task.amount
break
default:
task.desc = task.symbol + " " + task.action + ", 数量 " + task.amount
}
self.tasks.push(task) // 压入任务数组中
Log("接收到任务", task.desc) // 输出日志 显示 接收到任务。
}
self.cancelAll = function(e) { // 添加函数,取消所有,参数: 交易所对象
while (true) { // 遍历未完成的所有订单,逐个取消。
var orders = e.GetOrders();
if (!orders) { // 所有API 调用都不重试,如果API调用失败,立即返回。
return self.ERR_GET_ORDERS;
}
if (orders.length == 0) {
break;
}
for (var i = 0; i < orders.length; i++) {
e.CancelOrder(orders[i].Id);
Sleep(self.retryInterval);
}
}
return self.ERR_SUCCESS // 返回 完成标记
}
self.pollTask = function(task) { // 执行数组中弹出的任务
var insDetail = task.e.SetContractType(task.symbol); // 切换到当前 任务 task 对象保存的合约类型
if (!insDetail) { // 切换失败 立即返回
return self.ERR_SET_SYMBOL;
}
var ret = null;
var isCover = task.action != "buy" && task.action != "sell"; // 根据执行的动作,设置 是否是平仓的 标记
do { // do while 循环,先执行 do 以内
if (!$.IsTrading(task.symbol)) { // 判断是否在交易时间
return self.ERR_NOT_TRADING; // 不在交易时间立即返回
}
if (self.cancelAll(task.e) != self.ERR_SUCCESS) { // 调用全部取消函数 ,如果不等于 完成状态
return self.ERR_TRADE; // 返回交易失败
}
if (!CanTrade(task.amount)) { // 风控模块检测。
ret = null
break
}
var positions = task.e.GetPosition(); // 获取持仓信息
// Error
if (!positions) {
return self.ERR_GET_POS; // 如果调用获取持仓 API 错误,立即返回
}
// search position
var pos = null;
for (var i = 0; i < positions.length; i++) { // 遍历持仓信息,查找持仓合并持仓,类似 上面的 GetPosition 函数
if (positions[i].ContractType == task.symbol && (((positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD) && (task.action == "buy" || task.action == "closebuy")) || ((positions[i].Type == PD_SHORT || positions[i].Type == PD_SHORT_YD) && (task.action == "sell" || task.action == "closesell")))) {
if (!pos) {
pos = positions[i];
pos.Cost = positions[i].Price * positions[i].Amount;
} else {
pos.Amount += positions[i].Amount;
pos.Profit += positions[i].Profit;
pos.Cost += positions[i].Price * positions[i].Amount;
}
}
}
// record pre position
if (!task.init) { // 如果任务没有初始化,执行以下
task.init = true; // 更新为已初始化
if (pos) { // 如果查找到之前的持仓,把之前的持仓数量、 花费 复制给task 的相应变量保存
task.preAmount = pos.Amount;
task.preCost = pos.Cost;
} else { // 如果执行这个任务 时没有 ,同样的方向 同样合约的持仓,把task相关变量赋值0
task.preAmount = 0;
task.preCost = 0;
if (isCover) { // 如果是 平仓动作,输出日志 : 找不到仓位,跳出循环。
Log("找不到仓位", task.symbol, task.action);
ret = null;
break;
}
}
}
var remain = task.amount; // 声明一个局部变量,用 任务的属性 amount(任务设定的交易量) 初始化
if (isCover && !pos) { // 如果 第二次循环中 , 该任务动作是平仓,并且 没有持仓了,给pos 赋值
pos = {Amount:0, Cost: 0, Price: 0}
}
if (pos) { // 如果 pos 不为null
task.dealAmount = pos.Amount - task.preAmount; // 已经处理的任务量 等于 每次获取的持仓信息持仓量 与最初开始循环的初始持仓信息持仓量的差值
if (isCover) { // 如果是 平仓动作, dealAmount 是负值, 这里取反操作
task.dealAmount = -task.dealAmount;
}
remain = parseInt(task.amount - task.dealAmount); // 任务的 交易量 减去 已经处理的交易量 得出 剩余需要处理的交易量
if (remain <= 0 || task.retry >= task.maxRetry) { // 如果剩余需要的交易量小于等于0(此处分析应该是不会小于0,有兴趣的可以分析下。) 或者重试次数大于最大重试上限.
ret = { // 更新ret 对象, 更新为已经成交的信息,和 当前仓位信息。
price: (pos.Cost - task.preCost) / (pos.Amount - task.preAmount),
amount: (pos.Amount - task.preAmount),
position: pos
};
if (isCover) { // 如果是 平仓动作
ret.amount = -ret.amount; // 平仓时计算出的是负值 ,取反操作
if (pos.Amount == 0) { // 如果持仓量为0了, 把ret 的持仓信息 赋值为 null
ret.position = null;
}
}
break; // remain <= 0 || task.retry >= task.maxRetry 符合这个条件,跳出while循环
}
} else if (task.retry >= task.maxRetry) { // 如果不是 平仓操作。pos 为null 没有持仓(平仓操作 pos 此处不会是null)
ret = null; // 并且 该任务重试测试 大于最大重试次数。跳出循环。
break; // 即此时 , 超过最大重试次数,并且 没有增加持仓(开仓 每次都失败了。),跳出循环
}
var depth = task.e.GetDepth(); // 获取 深度数据
if (!depth) {
return self.ERR_GET_DEPTH; // 获取失败立即返回
}
var orderId = null; // 订单ID
var slidePrice = insDetail.PriceTick * SlideTick; // 计算具体滑价值
if (isCover) { // 如果是平仓操作
for (var i = 0; i < positions.length; i++) { // 遍历本轮的 API 返回的持仓信息。
if (positions[i].ContractType !== task.symbol) { // 不是当前任务 品种的 跳过。
continue;
}
if (parseInt(remain) < 1) { // 需要处理的 交易的量 如果小于1,跳出 while
break
}
var amount = Math.min(insDetail.MaxLimitOrderVolume, positions[i].Amount, remain); // 在合约规定的最大下单量、持仓量、需要处理的量中取最小值。
if (task.action == "closebuy" && (positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD)) { // 如果是平多仓, 持仓信息 为 今日多仓 或者 昨日多仓
task.e.SetDirection(positions[i].Type == PD_LONG ? "closebuy_today" : "closebuy"); // 设置方向
amount = Math.min(amount, depth.Bids[0].Amount) // 根据盘口量 和 下单量 再取一个最小值。
orderId = task.e.Sell(_N(depth.Bids[0].Price - slidePrice, 2), amount, task.symbol, positions[i].Type == PD_LONG ? "平今" : "平昨", 'Bid', depth.Bids[0]);
// 执行具体的 API 操作,以下平空类似
} else if (task.action == "closesell" && (positions[i].Type == PD_SHORT || positions[i].Type == PD_SHORT_YD)) {
task.e.SetDirection(positions[i].Type == PD_SHORT ? "closesell_today" : "closesell");
amount = Math.min(amount, depth.Asks[0].Amount)
orderId = task.e.Buy(_N(depth.Asks[0].Price + slidePrice, 2), amount, task.symbol, positions[i].Type == PD_SHORT ? "平今" : "平昨", 'Ask', depth.Asks[0]);
}
// assume order is success insert
remain -= amount; // 假设是成功执行, 需要处理的交易量 减去 此次交易的量。
}
} else { // 开仓
if (task.action == "buy") {
task.e.SetDirection("buy");
orderId = task.e.Buy(_N(depth.Asks[0].Price + slidePrice, 2), Math.min(remain, depth.Asks[0].Amount), task.symbol, 'Ask', depth.Asks[0]);
} else {
task.e.SetDirection("sell");
orderId = task.e.Sell(_N(depth.Bids[0].Price - slidePrice, 2), Math.min(remain, depth.Bids[0].Amount), task.symbol, 'Bid', depth.Bids[0]);
}
}
// symbol not in trading or other else happend
if (!orderId) { // 没有返回具体的ID ,可能是 交易不在交易队列,或者其他错误。
task.retry++; // 累计重试次数
return self.ERR_TRADE; // 返回错误信息。即使不成功, 重新 执行该任务的时候 会重新一次流程。除了task对象的数据 所有数据都会刷新
}
} while (true); // 循环判断 恒为真
task.finished = true // 如果在 while 循环中没有直接 return 顺序执行到此,则任务完成
if (self.onTaskFinish) { // 如果队列控制对象的 回调函数 设置 不为null(即 self.onTaskFinish 存在)
self.onTaskFinish(task, ret) // 执行回调函数。把 task 任务 对象 和 交易的结果 ret 对象 传入回调函数。
}
if (task.onFinish) { // 处理 任务的回调函数
task.onFinish(task, ret);
}
return self.ERR_SUCCESS;
}
self.poll = function() { // 迭代执行 弹出 tasks 中的任务 ,并调用 pollTask 执行任务。
var processed = 0 // 未执行完成的任务计数 ,每次初始0
_.each(self.tasks, function(task) { // 迭代 可以搜索 _.each 的用法
if (!task.finished) { // 如果 任务不是完成状态,
processed++ // 未完成任务 计数 累计
self.pollTask(task) // 执行弹出的任务
}
})
if (processed == 0) { // 如果没有未完成的任务,即 所有任务队列内的任务完成 ,执行清空 队列对象中 tasks 数组.
self.tasks = []
}
}
self.size = function() { // 给队列对象添加 函数 size 获取 任务队列 中 任务个数
return self.tasks.length
}
return self // 返回构造好的队列对象
}
$.AccountToTable = 계정에서 테이블로;