This commit is contained in:
botvs
2016-12-02 12:39:51 +08:00
parent 7a601205fa
commit 4e5424d37d
12 changed files with 1685 additions and 1343 deletions
+9 -6
View File
@@ -4,19 +4,22 @@
> 开源策略列表
- [商品期货跨期对冲](https://www.botvs.com/strategy/23896)
- [jLib借贷函数库](https://www.botvs.com/strategy/23943)
- [全球10大交易系统之 Aberration 多品种商品期货交易系统](https://www.botvs.com/strategy/25943)
- [商品期货交易类库](https://www.botvs.com/strategy/12961)
- [获取和讯期货数据(Python版本)](https://www.botvs.com/strategy/26017)
- [高频收割机一号](https://www.botvs.com/strategy/6237)
- [高精度回测](https://www.botvs.com/strategy/11575)
- [商品期货跨期对冲 - 百行代码实现](https://www.botvs.com/strategy/23896)
- [jLibPub_借贷函数库](https://www.botvs.com/strategy/23943)
- [R-Breaker 交易策略](https://www.botvs.com/strategy/23531)
- [多平台对冲稳定套利 V2.1 (复制)](https://www.botvs.com/strategy/23718)
- [从第三方网站获取K线 (0804更新)+ bitstamp+okcoin现货](https://www.botvs.com/strategy/21487)
- [CTP商品期货多品种海龟交易策略](https://www.botvs.com/strategy/17289)
- [商品期货交易类库](https://www.botvs.com/strategy/12961)
- [(13)策略框架](https://www.botvs.com/strategy/20663)
- [python版现货数字货币交易类库](https://www.botvs.com/strategy/21104)
- [Dual Thrust_双轨突破_策略1](https://www.botvs.com/strategy/22983)
- [Python 机器学习之 SVM 预测买卖](https://www.botvs.com/strategy/21370)
- [震荡突破策略 (删减B值触发平仓、动态调整触发值 优化ing)](https://www.botvs.com/strategy/22759)
- [顺势_高频_交易_测试3](https://www.botvs.com/strategy/22183)
- [测试CTP商品期货连接状态 (图表显示)](https://www.botvs.com/strategy/22838)
- [Python API 测试](https://www.botvs.com/strategy/21365)
- [均线策略(python版)](https://www.botvs.com/strategy/21157)
- [顺势_高频_交易_测试2——失败](https://www.botvs.com/strategy/21938)
@@ -53,7 +56,6 @@
- [窜天猴 - 移动止损版](https://www.botvs.com/strategy/13594)
- [窜天猴 多空较量 爆破版](https://www.botvs.com/strategy/13597)
- [破冰者](https://www.botvs.com/strategy/9929)
- [高精度回测](https://www.botvs.com/strategy/11575)
- [函数自动容错模板](https://www.botvs.com/strategy/11609)
- [Dual Thrust OKCoin 期货](https://www.botvs.com/strategy/12101)
- [RSI_now_sb_ok](https://www.botvs.com/strategy/11604)
@@ -69,6 +71,7 @@
- [均线买卖策略](https://www.botvs.com/strategy/143)
- [趋势跟踪震荡策略](https://www.botvs.com/strategy/179)
- [多平台账户统计](https://www.botvs.com/strategy/7827)
- [差价监控](https://www.botvs.com/strategy/7944)
- [计划委托买入](https://www.botvs.com/strategy/638)
- [计划委托卖出](https://www.botvs.com/strategy/747)
- [股票证券查询买卖示例](https://www.botvs.com/strategy/5541)
@@ -1,6 +1,6 @@
/*
策略出处: https://www.botvs.com/strategy/23943
策略名称: jLib借贷函数库
策略名称: jLibPub_借贷函数库
策略作者: J
策略描述:
@@ -1,87 +0,0 @@
/*
策略出处: https://www.botvs.com/strategy/21487
策略名称: 从第三方网站获取K线 (0804更新)+ bitstamp+okcoin现货
策略作者: 青铜战国级机器人
策略描述:
对于不支持获取K线数据的平台(BitVC期货、BTCC的BTC现货、中国比特币的ETH、ETC),如果在策略开始时必须获取足够多的K线,使用本模板则可从第三方网站直接获得平台的历史K线数据。
注意:
K线数据每3秒更新一次,因此无法高频调用。
仅适用于实盘交易。
作者不保证第三方数据准确性和程序正确性,仅供学习参考。
0427更新:处理了Parse JSON数据时可能抛出的异常、出现异常时返回值统一为null。
*/
$.AltRecords = function(exchange, timeframe, size, includeLastBar) {
var symbol;
var info;
var record = [];
if (!size) size="";
// 目前只支持以下三个交易所,其余交易所接口可参考https://www.btc123.com/api
if (exchange.GetName().indexOf('Futures_BitVC') != -1) {
symbol = "bitvcbtccnyfuture";
}
else if (exchange.GetName().indexOf('BTCC') != -1 && exchange.GetCurrency().indexOf('BTC') != -1) {
symbol = "btcchinabtccny";
}
else if (exchange.GetName().indexOf('CHBTC') != -1 && exchange.GetCurrency().indexOf('ETH') != -1) {
symbol = "chbtcethcny";
}
else if (exchange.GetName().indexOf('CHBTC') != -1 && exchange.GetCurrency().indexOf('ETC') != -1) {
symbol = "chbtcetccny";
}
else if (exchange.GetName().indexOf('CHBTC') != -1 && exchange.GetCurrency().indexOf('BTC') != -1) {
symbol = "chbtcbtccny";
}
else if (exchange.GetName().indexOf('Bitstamp') != -1 && exchange.GetCurrency().indexOf('BTC') != -1) {
symbol = "bitstampbtcusd";
}
else if (exchange.GetName().indexOf('Futures_OKCoin') != -1 && exchange.GetCurrency().indexOf('BTC') != -1) {
symbol = "okcoinbtcusdfuture";
}
else if (exchange.GetName().indexOf('OKCoin_EN') != -1 && exchange.GetCurrency().indexOf('BTC') != -1) {
symbol = "okcoinbtcusd";
}
else if (exchange.GetName().indexOf('OKCoin') != -1 && exchange.GetCurrency().indexOf('BTC') != -1) {
symbol = "okcoincnbtccny";
}
else if (exchange.GetName().indexOf('Huobi') != -1 && exchange.GetCurrency().indexOf('BTC') != -1) {
symbol = "huobibtccny";
}
else if (exchange.GetName().indexOf('BTCE') != -1 && exchange.GetCurrency().indexOf('BTC') != -1) {
symbol = "btcebtcusd";
}
if (symbol) {
try {
info = JSON.parse(HttpQuery('https://www.btc123.com/market/kline?symbol='+symbol+'&type='+timeframe+'&size='+(includeLastBar ? size : size+1)));
if (info && info.isSuc) {
info = JSON.parse(info.datas.data);
}
else {
Log("获取K线时发生错误:", info && info.des ? info.des : "网络错误");
return null;
}
} catch (e) {
Log("获取K线时发生错误:", info && info.des ? info.des : "网络错误");
return null;
}
for (var i = 0; i < (includeLastBar ? info.length : info.length-1); i++) {
record.push({"Time": info[i][0], "Open": info[i][1], "High": info[i][2], "Low": info[i][3], "Close": info[i][4], "Volume": info[i][5]});
}
return record;
}
return exchange.GetRecords(); // 不支持的交易所采用默认方式处理(忽略所有参数,如时间周期、长度等)。
};
function main() {
Log(exchange.GetName());
var rec = $.AltRecords(exchange, "5min", 100); // 获取5分钟K线, 100条, 不含最后一条Bar
if (rec) Log(rec.length, rec[rec.length-1]);
rec = $.AltRecords(exchange, "1hour", 1000000); // 获取4小时K线, 100条, 含最后一条Bar
Log(rec);
if (rec) Log(rec.length, rec[rec.length-1]);
}
@@ -0,0 +1,355 @@
/*
策略出处: https://www.botvs.com/strategy/25943
策略名称: 全球10大交易系统之 Aberration 多品种商品期货交易系统
策略作者: Zero
策略描述:
全球10大交易系统之一, 代码对细节处理很完善, 整体策略框架成熟稳定而且复用性强,逻辑清晰, 是做为商品期货多品种操作策略入门的不二之选
参数 默认值 描述
------------ ---------------------- ----------
Symbols MA701:5,CF701:3,rb1701 合约品种
NPeriod 35 计算周期
Ks 2 上轨系数
Kx 2 下轨系数
AmountOP true 默认开仓合约张数
LoopInterval 3 轮询间隔(秒)
NotifyWX true 下单微信通知
Reset false 启动时重置
RCMode true 启用风控模块
MinNetAsset 10000 最小净值
RCCoverAll true 触发后平掉所有仓位
AutoRestore false 自动根据仓位恢复进度
按钮 默认值 描述
----- -------------------------- ----
Debug Log(exchange.GetAccount()) 调试
*/
function Aberration(q, e, symbol, period, upRatio, downRatio, opAmount) {
var self = {}
self.q = q
self.e = e
self.symbol = symbol
self.upTrack = 0
self.middleTrack = 0
self.downTrack = 0
self.nPeriod = period
self.upRatio = upRatio
self.downRatio = downRatio
self.opAmount = opAmount
self.marketPosition = 0
self.lastErrMsg = ''
self.lastErrTime = ''
self.lastBar = {
Time: 0,
Open: 0,
High: 0,
Low: 0,
Close: 0,
Volume: 0
}
self.symbolDetail = null
self.lastBarTime = 0
self.tradeCount = 0
self.isBusy = false
self.setLastError = function(errMsg) {
self.lastErrMsg = errMsg
self.lastErrTime = errMsg.length > 0 ? _D() : ''
}
self.getStatus = function() {
return [self.symbol, self.opAmount, self.upTrack, self.downTrack, self.middleTrack, _N(self.lastBar.Close), (self.marketPosition == 0 ? "--" : (self.marketPosition > 0 ? "多#ff0000" : "空#0000ff")), self.tradeCount, self.lastErrMsg, self.lastErrTime]
}
self.getMarket = function() {
return [self.symbol, _D(self.lastBarTime), _N(self.lastBar.Open), _N(self.lastBar.High), _N(self.lastBar.Low), _N(self.lastBar.Close), self.lastBar.Volume]
}
self.restore = function(positions) {
for (var i = 0; i < positions.length; i++) {
if (positions[i].ContractType == self.symbol) {
self.marketPosition += positions[i].Amount * ((positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD) ? 1 : -1)
}
}
if (self.marketPosition !== 0) {
self.tradeCount++
Log("恢复", self.symbol, "当前持仓为", self.marketPosition)
}
}
self.poll = function() {
if (self.isBusy) {
return false
}
if (!$.IsTrading(self.symbol)) {
self.setLastError("不在交易时间内")
return false
}
if (!self.e.IO("status")) {
self.setLastError("未连接交易所")
return false
}
var detail = self.e.SetContractType(self.symbol)
if (!detail) {
self.setLastError("切换合约失败")
return false
}
if (!self.symbolDetail) {
self.symbolDetail = detail
Log("合约", detail.InstrumentName.replace(/\s+/g, ""), ", 策略一次开仓:", self.opAmount, "手, 一手", detail.VolumeMultiple, "份, 最大下单量", detail.MaxLimitOrderVolume, "保证金率:", detail.LongMarginRatio.toFixed(4), detail.ShortMarginRatio.toFixed(4), "交割日期", detail.StartDelivDate);
}
var records = self.e.GetRecords()
if (!records || records.length == 0) {
self.setLastError("获取柱线失败")
return false
}
var bar = records[records.length - 1]
self.lastBar = bar
if (records.length <= self.nPeriod) {
self.setLastError("柱线长度不够")
return false
}
if (self.lastBarTime < bar.Time) {
var sum = 0
var pos = records.length - self.nPeriod - 1
for (var i = pos; i < records.length - 1; i++) {
sum += records[i].Close
}
var avg = sum / self.nPeriod
var std = 0
for (i = pos; i < records.length - 1; i++) {
std += Math.pow(records[i].Close - avg, 2)
}
std = Math.sqrt(std / self.nPeriod)
self.upTrack = _N(avg + (self.upRatio * std))
self.downTrack = _N(avg - (self.downRatio * std))
self.middleTrack = _N(avg)
self.lastBarTime = bar.Time
}
var msg
var act = ""
if (self.marketPosition == 0) {
if (bar.Close > self.upTrack) {
msg = '做多 触发价: ' + bar.Close + ' 上轨:' + self.upTrack;
act = "buy"
} else if (bar.Close < self.downTrack) {
msg = '做空 触发价: ' + bar.Close + ' 下轨:' + self.downTrack;
act = "sell"
}
} else {
if (self.marketPosition < 0 && bar.Close > self.middleTrack) {
msg = '平空 触发价: ' + bar.Close + ' 平仓线:' + self.middleTrack;
act = "closesell"
} else if (self.marketPosition > 0 && bar.Close < self.middleTrack) {
msg = '平多 触发价: ' + bar.Close + ' 平仓线:' + self.middleTrack;
act = "closebuy"
}
}
if (act == "") {
return true
}
Log(self.symbol + ', ' + msg + (NotifyWX ? '@' : ''))
self.isBusy = true
self.tradeCount += 1
if (self.lastErrMsg != '') {
self.setLastError('')
}
self.q.pushTask(self.e, self.symbol, act, self.opAmount, function(task, ret) {
self.isBusy = false
if (!ret) {
return
}
if (task.action == "buy") {
self.marketPosition = 1
} else if (task.action == "sell") {
self.marketPosition = -1
} else {
self.marketPosition = 0
}
})
}
return self
}
function main() {
if (exchange.GetName() !== 'Futures_CTP') {
throw "只支持传统商品期货(CTP)"
}
SetErrorFilter("login|ready|初始化")
LogStatus("Ready...")
if (Reset) {
LogProfitReset()
LogReset()
}
// Ref: https://www.botvs.com/bbs-topic/362
if (typeof(exchange.IO("mode", 0)) == 'number') {
Log("切换行情模式成功")
}
LogStatus("等待与期货商服务器连接..")
while (!exchange.IO("status")) {
Sleep(500)
}
LogStatus("获取资产信息")
var tblRuntime = {
type: 'table',
title: '交易信息',
cols: ['品种', '每次开仓量', '上轨', '下轨', '中轨', '最后成交价', '仓位', '交易次数', '最后错误', '错误时间'],
rows: []
};
var tblMarket = {
type: 'table',
title: '行情信息',
cols: ['品种', '当前周期', '开盘', '最高', '最低', '最后成交价', '成交量'],
rows: []
};
var tblPosition = {
type: 'table',
title: '持仓信息',
cols: ['品种', '杠杆', '方向', '均价', '数量', '持仓盈亏'],
rows: []
};
var positions = _C(exchange.GetPosition)
if (positions.length > 0 && !AutoRestore) {
throw "程序启动时不能有持仓, 但您可以勾选自动恢复来进行自动识别 !"
}
var initAccount = _C(exchange.GetAccount)
var detail = JSON.parse(exchange.GetRawJSON())
if (positions.length > 0) {
initAccount.Balance += detail['CurrMargin']
}
var initNetAsset = detail['CurrMargin'] + detail['Available']
var initAccountTbl = $.AccountToTable(exchange.GetRawJSON(), "初始资金")
if (initAccountTbl.rows.length == 0) {
initAccountTbl.rows = [
['Balance', '可用保证金', initAccount.Balance],
['FrozenBalance', '冻结资金', initAccount.FrozenBalance]
]
}
var nowAcccount = initAccount
var nowAcccountTbl = initAccountTbl
var symbols = Symbols.replace(/\s+/g, "").split(',')
var pollers = []
var prePosUpdate = 0
var suffix = ""
var needUpdate = false
var holdProfit = 0
function updateAccount(acc) {
nowAcccount = acc
nowAcccountTbl = $.AccountToTable(exchange.GetRawJSON(), "当前资金")
if (nowAcccountTbl.rows.length == 0) {
nowAcccountTbl.rows = [
['Balance', '可用保证金', nowAcccount.Balance],
['FrozenBalance', '冻结资金', nowAcccount.FrozenBalance]
]
}
}
var q = $.NewTaskQueue(function(task, ret) {
needUpdate = true
Log(task.desc, ret ? "成功" : "失败")
var account = task.e.GetAccount()
if (account) {
updateAccount(account)
}
})
_.each(symbols, function(symbol) {
var pair = symbol.split(':')
pollers.push(Aberration(q, exchange, pair[0], NPeriod, Ks, Kx, (pair.length == 1 ? AmountOP : parseInt(pair[1]))))
})
if (positions.length > 0 && AutoRestore) {
_.each(pollers, function(poll) {
poll.restore(positions)
})
}
var isFirst = true
while (true) {
var cmd = GetCommand()
if (cmd) {
var js = cmd.split(':', 2)[1]
Log("执行调试代码:", js)
try {
eval(js)
} catch (e) {
Log("Exception", e)
}
}
tblRuntime.rows = []
tblMarket.rows = []
var marketAlive = false
_.each(pollers, function(poll) {
if (poll.poll()) {
marketAlive = true
}
tblRuntime.rows.push(poll.getStatus())
tblMarket.rows.push(poll.getMarket())
})
q.poll()
Sleep(LoopInterval * 1000)
if ((!exchange.IO("status")) || (!marketAlive)) {
if (isFirst) {
LogStatus("正在等待开盘...", _D())
}
continue
}
isFirst = false
var now = new Date().getTime()
if (marketAlive && (now - prePosUpdate > 30000 || needUpdate)) {
var pos = exchange.GetPosition()
if (pos) {
holdProfit = 0
prePosUpdate = now
tblPosition.rows = []
for (var i = 0; i < pos.length; i++) {
tblPosition.rows.push([pos[i].ContractType, pos[i].MarginLevel, ((pos[i].Type == PD_LONG || pos[i].Type == PD_LONG_YD) ? '多#ff0000' : '空#0000ff'), pos[i].Price, pos[i].Amount, _N(pos[i].Profit)])
holdProfit += pos[i].Profit
}
if (pos.length == 0 && needUpdate) {
LogProfit(_N(nowAcccount.Balance - initAccount.Balance, 4), nowAcccount)
}
}
needUpdate = false
if (RCMode) {
var account = exchange.GetAccount()
if (account) {
updateAccount(account)
var detail = JSON.parse(exchange.GetRawJSON())
var netAsset = detail['PositionProfit'] + detail['CurrMargin'] + detail['Available']
var risk = detail['CurrMargin'] / (detail['CurrMargin'] + detail['Available'] + detail['PositionProfit'])
suffix = ", 账户初始净值约: " + _N(initNetAsset, 2) + " , 风控最小净值要求" + MinNetAsset + " , 当前账户净值约: " + _N(netAsset, 2) + ", 盈亏约: " + _N(netAsset - initNetAsset, 3) + " 元, 风险: " + ((risk * 100).toFixed(3)) + "% #ff0000"
if (netAsset < MinNetAsset) {
Log("风控模块触发, 中止运行并平掉所有仓位, 当前净值约 ", netAsset, ", 要求低于最小净值:", MinNetAsset)
if (RCCoverAll) {
Log("开始平掉所有仓位")
$.NewPositionManager().CoverAll()
}
throw "中止运行"
}
}
}
}
LogStatus('`' + JSON.stringify([tblRuntime, tblPosition, tblMarket, initAccountTbl, nowAcccountTbl]) + '`\n价格最后更新: ' + _D() + ', 持仓最后更新: ' + _D(prePosUpdate) + '\n当前持仓总盈亏: ' + _N(holdProfit, 3) + suffix)
}
}
File diff suppressed because it is too large Load Diff
@@ -1,25 +1,27 @@
/*
策略出处: https://www.botvs.com/strategy/23896
策略名称: 商品期货跨期对冲
策略名称: 商品期货跨期对冲 - 百行代码实现
策略作者: Zero
策略描述:
简单的跨期对冲, 抛砖引玉, 细节还需要处理
简单的跨期对冲, 抛砖引玉, 细节还需要处理, 轮训间隔可以缩小到1秒或者删除Sleep那行策略就可以随时响应价格变化
参数 默认值 描述
------------ ----- -------
HedgeSpread 30 开仓价差
CoverSpread 10 平仓价差
LoopInterval true 轮询间隔(秒)
------------ ----- ---------
SA MA701 合约A
SB MA705 合约B
HedgeSpread 30 开仓价差
CoverSpread 10 平仓价差
LoopInterval 6 轮询间隔(秒)
CoverAll false 启动时平掉所有仓位
*/
function Hedge(q, e, symbolA, symbolB, hedgeSpread, coverSpread) {
function Hedge(q, e, initAccount, symbolA, symbolB, hedgeSpread, coverSpread) {
var self = {}
self.q = q
self.initAccount = initAccount
self.status = 0
self.symbolA = symbolA
self.symbolB = symbolB
@@ -48,7 +50,8 @@ function Hedge(q, e, symbolA, symbolB, hedgeSpread, coverSpread) {
if (!tickerB) {
return
}
LogStatus("A卖B买", _N(tickerA.Buy - tickerB.Sell), "A买B卖", _N(tickerA.Sell-tickerB.Buy))
// _D()是内置时间格式化函数, 不传参就是取当前时间, 可以传时间戳
LogStatus(_D(), "A卖B买", _N(tickerA.Buy - tickerB.Sell), "A买B卖", _N(tickerA.Sell-tickerB.Buy))
var action = 0; // 1: A sell B buy 2: A buy B sell
if (self.status == 0) {
@@ -89,6 +92,8 @@ function Hedge(q, e, symbolA, symbolB, hedgeSpread, coverSpread) {
self.status = 1
} else {
self.status = 0
var account = _C(exchange.GetAccount)
LogProfit(account.Balance - self.initAccount.Balance, account)
}
})
})
@@ -98,17 +103,22 @@ function Hedge(q, e, symbolA, symbolB, hedgeSpread, coverSpread) {
function main() {
SetErrorFilter("ready|login|timeout")
Log("正在与交易服务器连接...")
while (!exchange.IO("status"))Sleep(1000);
Log("与交易服务器连接成功")
var initAccount = _C(exchange.GetAccount)
Log(initAccount)
var n = 0
var q = $.NewTaskQueue(function(task, ret) {
Log(task.desc, ret ? "成功" : "失败")
n++
if (n % 4 == 0) {
var account = _C(exchange.GetAccount)
LogProfit(account.Balance - initAccount.Balance, account)
}
})
var t = Hedge(q, exchanges[0], SA, SB, HedgeSpread, CoverSpread)
if (CoverAll) {
Log("开始平掉所有残余仓位...");
$.NewPositionManager().CoverAll();
Log("操作完成");
}
var t = Hedge(q, exchanges[0], initAccount, SA, SB, HedgeSpread, CoverSpread)
while (true) {
q.poll()
t.poll()
+43 -62
View File
@@ -1,7 +1,7 @@
/*
策略出处: https://www.botvs.com/strategy/1340
策略出处: https://www.botvs.com/strategy/7944
策略名称: 差价监控
策略作者: Zero
策略作者: 折腾中
策略描述:
只支持两个交易所, 可自定义差价的类型, 支持2.77托管者的自定义图表功能
@@ -17,10 +17,6 @@ EnableCR false 自定义汇率
USDCNY false USDCNY
NormalDiff 0.1 普通差价
HighDiff 0.3 较高差价
按钮 默认值 描述
---- ---------- ----
重置数据 __button__ @
*/
@@ -28,51 +24,6 @@ var __lastDiff = 0;
var __AType = ["Last", "Buy", "Sell"][AType];
var __BType = ["Last", "Buy", "Sell"][BType];
var cfg = {
tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},
title : { text : '差价分析图'},
rangeSelector: {
buttons: [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}],
selected: 0,
inputEnabled: false
},
xAxis: { type: 'datetime'},
yAxis : {
plotLines : [{
value : 0.0,
color : 'black',
dashStyle : 'shortdash',
width : 3,
}, {
value : NormalDiff,
color : 'green',
dashStyle : 'shortdash',
width : 1,
}, {
value : HighDiff,
color : 'red',
dashStyle : 'shortdash',
width : 1,
},{
value : -NormalDiff,
color : 'green',
dashStyle : 'shortdash',
width : 1,
}, {
value : -HighDiff,
color : 'red',
dashStyle : 'shortdash',
width : 1,
}]
},
series : [{
name : '价差',
data : [],
tooltip: {
valueDecimals: 2
}
}]
};
function _N(v, precision) {
if (typeof(precision) != 'number') {
precision = 4;
@@ -110,9 +61,6 @@ function onTick() {
}
if (diff != __lastDiff) {
// add添加数据到series, 参数格式为[series序号, 数据];
cfg.yAxis.plotLines[0].value=diff;
cfg.subtitle={text:'当前价差:' + diff};
__chart.update(cfg);
__chart.add([0, [new Date().getTime(), diff]]);
__lastDiff = diff;
}
@@ -126,7 +74,46 @@ function main() {
throw "只支持两个交易所对冲";
}
// 传给Chart函数的必须是一个与上下文无关的结构体(附合HighStocks规则, 详情参数HighStocks使用方法)
__chart = Chart(cfg);
__chart = Chart({
tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},
title : { text : '差价分析图'},
rangeSelector: {
buttons: [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}],
selected: 0,
inputEnabled: false
},
xAxis: { type: 'datetime'},
yAxis : {
plotLines : [{
value : NormalDiff,
color : 'green',
dashStyle : 'shortdash',
width : 1,
}, {
value : HighDiff,
color : 'red',
dashStyle : 'shortdash',
width : 1,
},{
value : -NormalDiff,
color : 'green',
dashStyle : 'shortdash',
width : 1,
}, {
value : -HighDiff,
color : 'red',
dashStyle : 'shortdash',
width : 1,
}]
},
series : [{
name : '价差',
data : [],
tooltip: {
valueDecimals: 2
}
}]
});
// reset 清空所有图表之前的信息
// __chart.reset();
if (EnableCR) {
@@ -134,7 +121,7 @@ function main() {
var rate = exchanges[i].GetRate();
if (rate != 1) {
exchanges[i].SetRate(USDCNY);
Log("更改", exchanges[i].GetName(), "汇率", rate, "为", USDCNY);
Log("更改", exchanges[i].GetName(), "汇率", rate, "为", USDCNY)
}
var eName = exchanges[i].GetName();
if (eName == "Futures_BitVC") {
@@ -148,11 +135,5 @@ function main() {
while (true) {
onTick();
Sleep(TickInterval);
if (GetCommand() === '重置数据') {
LogReset();
LogProfitReset();
__chart.reset();
Log("数据重置成功");
}
}
}
@@ -0,0 +1,166 @@
/*
策略出处: https://www.botvs.com/strategy/22838
策略名称: 测试CTP商品期货连接状态 (图表显示)
策略作者: 小小梦
策略描述:
测试CTP商品期货连接状态
1、图标显示
参数 默认值 描述
---------------- ----- -------
testContractType MA701 测试的合约类型
*/
//获取多个品种的信息 SR', 'CF', 'RM', 'MA', 'PTA', 'ZC', 'FG', 'IO
var ChartCfg = {
__isStock: true,
title: {
text: 'CTP商品期货 交易所连接状态记录'
},
xAxis:{type: 'datetime'},
yAxis: {
//tickInterval: 1,
//tickAmount: 3,
max: 1.5,
min: -1.5,
plotLines: [{
value: 0,
color: 'red',
width: 5,
label: {
text: '已连接',
align: 'center'
},
}, {
value: 0,
color: 'green',
width: 5,
label: {
text: '未连接',
align: 'center'
},
}]
},
series: [{
type: 'line',
name: '连接状态',
id: 'state',
data: []
}, {
type: 'flags',
onSeries: 'state',
data: [],
}]
};
var ContractArray = ['SR701', 'CF701', 'RM701', 'MA701', 'ZC701', 'FG701']; //
function GetSomeContractMarketInfo(ContractArray){
var array = []; //储存获取的信息
_.each(ContractArray,function(ContractType){
exchange.SetContractType(ContractType);
array.push({TypeName : ContractType ,ticker : exchange.GetTicker()});
});
for(var i = 0 ; i < array.length; i++){
Log(array[i]);
}
return array;
}
var table = null;
function main() {
Log("测试CTP商品期货连接状态");
SetErrorFilter("login|ready");
//初始化图表
table = $.TableInit(3,6);
table.a0 = "实时状态:exchange.IO('status') ↓";
table.b0 = "test ContractType ↓";
table.c0 = "infomation ↓";
table.b2 = "ticker ↓#FF0000";
table.b4 = "records[-1] ↓#FF0000";
table.c2 = "Account ↓#FF0000";
//初始化 图
chart = Chart(ChartCfg);
ChartCfg.yAxis.plotLines[0].value = 1.1;
ChartCfg.yAxis.plotLines[1].value = -1.1;
chart.reset();
var state = null;
var isAlert = false;
var ConnectAlert = false;
var info = exchange.SetContractType(testContractType);//设置合约
Log("info:",info);
exchange.IO("mode",0);//设置行情 为立即返回模式
var lastState = null;
while(true){
state = exchange.IO("status");
if((state === true && lastState === false)){
info = exchange.SetContractType(testContractType);
while(info === null){
state = exchange.IO("status");
info = exchange.SetContractType(testContractType);
//LogStatus("state:",state,"lastState:",lastState,"info:",info," 登录 ,重新 设置 合约类型!");
table.a1 = state;
table.b1 = testContractType;
table.c1 = "等待登录 ,重新 设置 合约类型。";
if(state === false && lastState === true){
chart.add(0,[(new Date()).getTime(),-1]);
}else if(state === true && lastState === false){
chart.add(0,[(new Date()).getTime(),1]);
}
chart.update(ChartCfg);
Sleep(1000 * 60);
}
}
if(state === true){
var ticker = exchange.GetTicker();
var records = exchange.GetRecords();
//LogStatus("exchange.IO('status') `s state is:",state,"\n",ticker,"\n",records?records[records.length - 1] : records,"\n",exchange.GetAccount(),"\n",new Date(),"\n",info);
table.a1 = state;
table.b1 = testContractType;
table.b3 = ticker;
if(records === null){
table.b5 = "null";
}else if(records.length > 0){
table.b5 = records[records.length - 1];
}
table.c3 = exchange.GetAccount();
if(ConnectAlert === false){
Log("state:",state,"info:",info,"#99CC32");
ConnectAlert = true;
}
//LogStatus("exchange.IO('status') `s state is:",state);
//GetSomeContractMarketInfo(ContractArray);
isAlert = false;
}else{
//LogStatus("exchange.IO('status') `s state is:",state,"time:",new Date(),"\n",info);
table.a1 = state;
if(isAlert === false){
Log("state:",state,"info:",info,"#FF0000");
Log("CTP商品期货测试微信提醒!state:" + state + "@");
info = null;
isAlert = true;
}
ConnectAlert = false;
}
//Log(exchange.IO("status"));
//Log("ceshi");
//记录状态到图表
if(state === false && lastState === true){
chart.add(0,[(new Date()).getTime(),-1]);
}else if(state === true && lastState === false){
chart.add(0,[(new Date()).getTime(),1]);
}
chart.update(ChartCfg);
$.UpdateLogStatus("time:" + (new Date())); //更新 状态栏 图表内容
lastState = state; //当前状态更新到上次状态
Sleep(1000 * 5);
}
}
@@ -0,0 +1,84 @@
'''
策略出处: https://www.botvs.com/strategy/26017
策略名称: 获取和讯期货数据(Python版本)
策略作者: edwardgyw
策略描述:
数狂很早之前写了个js版本的第三方数据获取,我照着他的改写了个python版本的,可以下在云服务器上引入自己的包,这样研究时候也可以用。
update 12.01 和讯接口有变化多了60分钟和周线的信息,原版选择1440会获取60分钟的k线,这里fix了
'''
#coding: utf-8
import urllib2 as url
import json
import time
def hxRecords(instrument,timeFrame=1,size=1,includeLastBar=True,to_df=True):
##从和讯获取期货实时数据
pInst=instrument.lower()
if pInst[-4]!='1':
pInst=pInst[:-3]+'1'+pInst[-3:]
xchg=None
for i in instList:
if pInst[:-4] in i['inst']:
xchg=i['xchg']
if xchg is None:
print ("获取K线时发生错误: 找不到合约")
return None
tfs=[1,5,15,30,60,'D','W']
tf=None
for i in range(len(tfs)):
if timeFrame==tfs[i]:
tf=i
if tf is None:
print("获取K线时发生错误: K线周期不正确")
return None
now=time.localtime()
timestr=str(now.tm_year+1)+str(12)+str(31)+'000000'
resp='http://webftcn.hermes.hexun.com/shf/kline?code=' + xchg + pInst + '&start=' + timestr + '&number=-' + str(size) + '&type=' + str(tf)
try:
resp=url.urlopen(resp)
resp=resp.read()[1:-2]
resp=json.loads(resp)['Data']
except:
print '获取K线时发生错误: 不完整的JSON数据'
return None
re=[]
pw=float(resp[4])
for i in resp[0]:
res=dict(Time=time.mktime(time.strptime(str(i[0]),'%Y%m%d%H%M%S'))*1000,Open=i[2]/pw,High=i[4]/pw
,Low=i[5]/pw,Close=i[3]/pw,Volume=i[6])
re.append(res)
if to_df:
re=pd.DataFrame(re)
col=[]
for i in re.columns:
if i is 'Time':
i='Date'
col.append(i.lower())
re.columns=col
re['date']=re['date'].map(ts_dt64)
return re
instList = [{
"xchg": "SHFE",
"inst": ["fu", "ru", "wr"]
}, {
"xchg": "SHFE2",
"inst": ["ag", "au"]
}, {
"xchg": "SHFE3",
"inst": ["al", "bu", "cu", "hc", "ni", "pb", "rb", "sn", "zn"]
}, {
"xchg": "CZCE",
"inst": ["cf", "fg", "lr", "ma", "oi", "pm", "ri", "rm", "rs", "sf", "sm", "sr", "ta", "wh", "zc"]
}, {
"xchg": "DCE",
"inst": ["a", "b", "bb", "c", "cs", "fb", "i", "j", "jd", "jm", "l", "m", "p", "pp", "v", "y"]
}]
def main():
Log(exchange.GetAccount())
@@ -1,532 +0,0 @@
/*
策略出处: https://www.botvs.com/strategy/22759
策略名称: 震荡突破策略 (删减B值触发平仓、动态调整触发值 优化ing)
策略作者: 小小梦
策略描述:
1、吃单优化为在触发值上挂单
2、止损仓 在被套的情况下开启止损仓。
3、动态阀值
4、加入 STOCHRSI 指标
参数 默认值 描述
---------------- ----- -------------
NPeriod 4 计算周期
Ks 0.5 上轨系数
Kx 0.5 下轨系数
AmountOP true 开仓量
Interval 2000 重试间隔(毫秒)
LoopInterval 3 轮询间隔(秒)
PeriodShow 500 图表最大显示K线柱数
InitMoveStop -20 初始止损值
step 5 滑动止损步长
isShowTouchLine true 显示触发值
isCurrentKLineOP true 是否允许当前K线平仓后交易
*/
var ChartCfg = {
__isStock: true,
title: {
text: '震荡突破策略'
},
yAxis: [{
title: {text: 'KL'},//标题
style: {color: '#4572A7'},//样式
opposite: false, //生成右边Y轴
plotLines: [{
value: 0,
color: 'red',
width: 2,
label: {
text: '触发值A',
align: 'center'
},
}, {
value: 0,
color: 'green',
width: 2,
label: {
text: '触发值B',
align: 'center'
},
}]
},
{
title:{text: "STOCHRSI"},
opposite: true //生成右边Y轴 ceshi
}
],
series: [{
type: 'candlestick',
name: '当前周期',
id: 'primary',
data: []
}, {
type: 'flags',
onSeries: 'primary',
data: [],
},{
type: 'spline',
yAxis: 1,
name: 'F',
data: []
},{
type: 'spline',
yAxis: 1,
name: 'S',
data: []
}]
};
/*
plotLines: [{
value: 0,
color: 'red',
width: 2,
label: {
text: '触发值A',
align: 'center'
},
}, {
value: 0,
color: 'green',
width: 2,
label: {
text: '触发值B',
align: 'center'
},
}]
*/
var STATE_IDLE = 0;
var STATE_LONG = 1;
var STATE_SHORT = 2;
var State = STATE_IDLE;
var LastBarTime = 0;
var UpTrack = 0;
var BottomTrack = 0;
var chart = null;
var InitAccount = null;
var Counter = {
w: 0,
l: 0
};
function LLV(array,period){
if(!array || array.length - period < 0){
throw "error:" + array;
}
var min = array[array.length - period];
for(var i = array.length - period; i < array.length; i++){
if( array[i] < min ){
min = array[i];
}
}
return min;
}
function HHV(array,period){
if(!array || array.length - period < 0){
throw "error:" + array;
}
var max = array[array.length - period];
for(var i = array.length - period; i < array.length; i++){
if( array[i] > max){
max = array[i];
}
}
return max;
}
function DeleteNullEle(initArr){
var dealArr = [];
var initArrLen = initArr.length;
for(var i = 0,j = 0 ; i < initArrLen ; i++,j++){
if(initArr[i] === null || isNaN(initArr[i]) ){
j--;
continue;
}
dealArr[j] = initArr[i];
}
return dealArr;
}
function FstochRSI(records,n,m,p1,p2){
var len = records.length;
//var LC = records[len-2];//上一周期收盘价
//var rsi = TA.RSI(records,n);// RSI 数组 ,talib
var rsi = talib.RSI(records,n);
rsi = DeleteNullEle(rsi);//ceshi
var arr1 = [];
var arr2 = [];
var arr3 = [];
var arr4 = [];
var rsi_a = [];
var rsi_b = [];
var k = [];
var d = null;
for(var a = 0 ;a < rsi.length ; a++ ){//改造 不用 LLV
if(a < m){
continue;
}
for(var aa = 0 ; aa <= a; aa++ ){
rsi_a.push(rsi[aa]);
}
arr1.push(rsi[a] - LLV(rsi_a,m));
}
for(var b = 0 ;b < rsi.length ; b++ ){//改造 不用 HHV
if(b < m){
continue;
}
for(var bb = 0 ; bb <= b; bb++ ){
rsi_b.push(rsi[bb]);
}
arr2.push(HHV(rsi_b,m) - LLV(rsi_b,m));
}
arr1 = DeleteNullEle(arr1);
arr2 = DeleteNullEle(arr2);
//Log("arr1:",arr1.length,"-",arr1);//ceshi
//Log("arr2:",arr2.length,"-",arr2);//ceshi
arr3 = talib.MA(arr1,p1);
arr4 = talib.MA(arr2,p1);
arr3 = DeleteNullEle(arr3);
arr4 = DeleteNullEle(arr4);
//Log("ceshi");//ceshi
var c = 0;
var diff = 0;
if(arr3.length !== arr4.length){//实测 长度不相等
throw "error: !=" + arr3.length + "----" + arr4.length;
diff = arr4.length - arr3.length; //example diff = 10 - 6
}else{
//throw "error:" + arr3.length + "----" + arr4.length;
}
for( ;c < arr3.length ; c++ ){
k.push(arr3[c] / arr4[c + diff] * 100);
}
d = talib.MA(k,p2);
return [k,d,rsi];
}
function CancelPendingOrders() {
while (true) {
var orders = exchange.GetOrders();
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
Sleep(Interval);
}
if (orders.length === 0) {
break;
}
}
}
var isBegin = false;
var isTrade_OC = false;
var stochrsiFast = 0;
var stochrsiSlow = 0;
function onTick(exchange) {
var records = exchange.GetRecords();
if (!records || (records.length < 50 || records.length <= NPeriod)) { //默认 STOCHRSI 指标 最大周期14 限制
return;
}
//Log(records.length);//ceshi
//throw "stop"; //ceshi
var stochrsi = FstochRSI(records,14,14,3,3); // 计算 STOCHRSI 指标
var Bar = records[records.length - 1];
if (LastBarTime !== Bar.Time) {
isTrade_OC = false;
var HH = TA.Highest(records, NPeriod, 'High');
var HC = TA.Highest(records, NPeriod, 'Close');
var LL = TA.Lowest(records, NPeriod, 'Low');
var LC = TA.Lowest(records, NPeriod, 'Close');
var Range = Math.max(HH - LC, HC - LL);
UpTrack = _N(Bar.Open + (Ks * Range));
DownTrack = _N(Bar.Open - (Kx * Range));
//更新触发值
table.a3 = UpTrack;
table.b3 = DownTrack;
if (LastBarTime > 0) {
var PreBar = records[records.length - 2];
chart.add(0, [PreBar.Time, PreBar.Open, PreBar.High, PreBar.Low, PreBar.Close], -1);
chart.add(2,[records[records.length - 2].Time,stochrsi[0][stochrsi[0].length - 2]], -1); //增加 快线
chart.add(3,[records[records.length - 2].Time,stochrsi[1][stochrsi[1].length - 2]], -1); //增加 慢线
} else {
for (var i = Math.min(records.length, NPeriod * 3); i > 1; i--) {
var b = records[records.length - i];
//Log(stochrsi[0][stochrsi[0].length - 1],stochrsi[1][stochrsi[1].length - 1]);//ceshi
chart.add(0, [b.Time, b.Open, b.High, b.Low, b.Close]);
if(isBegin === false){
chart.add(1, {x:(new Date()).getTime(), color: "black", shape: 'flag', title: "title", text: "开始"});
isBegin = true;
}
//chart.add(2,[records[records.length - 1].Time,stochrsi[0][stochrsi[0].length - 1]]); //增加快线
//chart.add(3,[records[records.length - 1].Time,stochrsi[1][stochrsi[1].length - 1]]); //增加慢线
}
}
chart.add(0, [Bar.Time, Bar.Open, Bar.High, Bar.Low, Bar.Close]);
chart.add(2,[records[records.length - 2].Time,stochrsi[0][stochrsi[0].length - 2]]); //增加 快线
chart.add(3,[records[records.length - 2].Time,stochrsi[1][stochrsi[1].length - 2]]); //增加 慢线
if(isShowTouchLine === true){//是否显示触发值
ChartCfg.yAxis[0].plotLines[0].value = UpTrack;
ChartCfg.yAxis[0].plotLines[1].value = DownTrack;
}
ChartCfg.subtitle = {
text: '触发值A: ' + UpTrack + ' 触发值B: ' + DownTrack
};
chart.update(ChartCfg);
//chart.reset(PeriodShow); //ceshi 取消
LastBarTime = Bar.Time;
} else {
chart.add(0, [Bar.Time, Bar.Open, Bar.High, Bar.Low, Bar.Close], -1);
chart.add(2,[records[records.length - 1].Time,stochrsi[0][stochrsi[0].length - 1]], -1); // 增加 快线
chart.add(3,[records[records.length - 1].Time,stochrsi[1][stochrsi[1].length - 1]], -1); // 增加 慢线
}
//Log(stochrsi);//ceshi
//LogStatus("Price:", Bar.Close, "Up:", UpTrack, "Down:", DownTrack, "Wins: ", Counter.w, "Losses:", Counter.l, "Date:", new Date(),"\n",NowPositionInfo);
var msg;
var fcolor = null;
var ftitle = "";
stochrsiFast = table.a6 = stochrsi[0][stochrsi[0].length - 1];
stochrsiSlow = table.b6 = stochrsi[1][stochrsi[1].length - 1];
if((isTrade_OC === true && isCurrentKLineOP === false) && ( isTurnOP_Long === false && isTurnOP_Short === false ) ){//是否允许当前K线交易,排除反手的条件
return;
}
if (State === STATE_IDLE) {
if ( isTurnOP_Long || (Bar.Close >= UpTrack && stochrsiFast < 30 && isTurnOP_Short === false) ) { // 加入STOCHRSI 控制
msg = '做多 触发价: ' + Bar.Close + ' 触发值A:' + UpTrack + "stochrsiFast" + stochrsiFast;
if(isTurnOP_Long === true){
msg = "反手做多" + msg + "#FF0000";
}
Log(msg);
buyInfo = $.Buy(AmountOP);
State = STATE_LONG;
Log("buyInfo:",buyInfo);
if(buyInfo === null){
return;
}
if(NowPositionInfo.direction === NONE){
NowPositionInfo.direction = LONG;
fcolor = 'red';
ftitle = 'L';
moveStop = InitMoveStop; //设置 默认止损额度
moveLevel = 0;
lastMoveStop = 0;
}
chart.add(1, {x:(new Date()).getTime(), color: fcolor, shape: 'flag', title: ftitle, text: msg});
}
}
if (State === STATE_IDLE) {
if ( isTurnOP_Short || (Bar.Close <= DownTrack && stochrsiFast > 70 && isTurnOP_Long === false) ) {//是否触发 反手 加入 STOCHRSI 控制
msg = '做空 触发价: ' + Bar.Close + ' 触发值B:' + DownTrack + "stochrsiFast" + stochrsiFast;
if(isTurnOP_Short === true){
msg = "反手做空" + msg + "#FF0000";
}
Log(msg);
sellInfo = $.Sell(AmountOP);
Log("sellInfo:",sellInfo);
if(sellInfo === null){
return;
}
State = STATE_SHORT;
if(NowPositionInfo.direction === NONE){
NowPositionInfo.direction = SHORT;
fcolor = 'green';
ftitle = 'S';
moveStop = InitMoveStop; //设置默认止损额度
moveLevel = 0;
lastMoveStop = 0;
}
chart.add(1, {x:(new Date()).getTime(), color: fcolor, shape: 'circlepin', title: ftitle, text: msg});
}
}
//滑动止损
if( (State === STATE_SHORT && NowPositionInfo.direction === SHORT ) || ( NowPositionInfo.direction === LONG && State === STATE_LONG) ){
if(NowPositionInfo.floatProfit > step){//滑动止损 结束后 lastMoveStop 要赋值 0 , moveLevel 要赋值 0 , moveStop 重新赋值初始止损值
moveStop = 0;
if(NowPositionInfo.floatProfit - lastMoveStop > step){
lastMoveStop = (++moveLevel) * step;
}
}
table.b5 = "lastLine" + lastMoveStop + ", Level" + moveLevel + " ,default" + moveStop;
//Log("NowPositionInfo",NowPositionInfo,"止损",moveStop + moveLevel * step); //ceshi
if(NowPositionInfo.floatProfit <= moveStop + moveLevel * step ){
//cover
//Log("NowPositionInfo",NowPositionInfo,"止损",moveStop + moveLevel * step); //ceshi
if(NowPositionInfo.direction === SHORT){//空仓止损
buyInfo = $.Buy(NowPositionInfo.amount);
if(buyInfo === null){
return;
}
isTurnOP_Short = false;//重置 反手条件为false
isTurnOP_Long = false;//重置 反手条件为false
State = STATE_IDLE;
Log("止损平仓",NowPositionInfo,"moveStop + moveLevel * step",moveStop + moveLevel * step,_C(exchange.GetTicker),buyInfo);//ceshi
CalculateCounter(buyInfo);//处理Counter 计数
NowPositionInfo.direction = NONE;
Calculate();
InitAccount = _C(exchange.GetAccount);
LogProfit(Profit,InitAccount);
fcolor = 'blue';
ftitle = '止损 平仓';
msg = "moveLevel:" + moveLevel + ", lastMoveStop:" + lastMoveStop;
isTrade_OC = true;//当前bar 已经交易
if(moveStop !== 0){//突破止损反手
isTurnOP_Long = true;
}
}
if(NowPositionInfo.direction === LONG){//多仓止损
sellInfo = $.Sell(NowPositionInfo.amount);
if(sellInfo === null){
return;
}
isTurnOP_Long = false;//重置反手条件为false
isTurnOP_Short = false;//重置反手条件为false
State = STATE_IDLE;
Log("止损平仓",NowPositionInfo,"moveStop + moveLevel * step",moveStop + moveLevel * step,_C(exchange.GetTicker),sellInfo);//ceshi
CalculateCounter(sellInfo);//处理Counter 计数
NowPositionInfo.direction = NONE;
Calculate();
InitAccount = _C(exchange.GetAccount);
LogProfit(Profit,InitAccount);
fcolor = 'blue';
ftitle = '止损 平仓';
msg = "moveLevel:" + moveLevel + ", lastMoveStop:" + lastMoveStop;
isTrade_OC = true;//当前bar 已经交易
if(moveStop !== 0){//突破止损反手
isTurnOP_Short = true;
}
}
chart.add(1, {x:(new Date()).getTime(), color: fcolor, shape: 'circlepin', title: ftitle, text: msg});
}
}
}
//反手
var isTurnOP_Long = false;
var isTurnOP_Short = false;
//滑动止损 参数
//var step = 5; //滑动步长
var moveStop = InitMoveStop; //初始止损
var lastMoveStop = 0; //上次止损挡位
var moveLevel = 0; //止损等级
//var OpAmount = 1;//ceshi
//var maxProfit = 0.2;
var buyInfo = null;
var sellInfo = null;
var SHORT = 2;
var LONG = 1;
var NONE = 0;
var NowPositionInfo = { //
avgPrice : 0 ,
amount : 0,
floatProfit : 0,
direction : 0 // 0 未持仓 , 1多仓 , 2空仓
};
function CalculateCounter(CoverInfo) {
if(NowPositionInfo.direction === STATE_LONG && (CoverInfo.price - NowPositionInfo.avgPrice > 0)){//处理多仓
Counter.w++;
}else if(NowPositionInfo.direction === STATE_LONG){
Counter.l++;
}
if(NowPositionInfo.direction === STATE_SHORT && (NowPositionInfo.avgPrice - CoverInfo.price > 0)){//处理空仓
Counter.w++;
}else if(NowPositionInfo.direction === STATE_SHORT){
Counter.l++;
}
table.b4 = Counter; //更新 Counter
}
var Profit = 0;
function Calculate(nowAccount,nowDepth){//计算并更新收益 、 浮动收益 、计算 持仓均价 、持仓量
if(typeof(nowAccount) === 'undefined' ){
nowAccount = _C(exchange.GetAccount);
nowDepth = _C(exchange.GetDepth);
}
var diff_stocks = nowAccount.Stocks - InitAccount.Stocks;//币之差
var diff_balance = nowAccount.Balance - InitAccount.Balance;//钱之差
NowPositionInfo.avgPrice = _N(Math.abs(diff_balance) / Math.abs(diff_stocks),5);
//throw nowAccount.Stocks + "----" + nowAccount.Balance;//ceshi
NowPositionInfo.amount = _N(Math.abs(diff_stocks),5);
NowPositionInfo.floatProfit = _N(diff_balance + diff_stocks * (NowPositionInfo.direction === LONG?nowDepth.Bids[0].Price : nowDepth.Asks[0].Price),5); //此次交易的浮动盈亏
Profit = (nowAccount.Stocks - beginAccount.Stocks) * (NowPositionInfo.direction === LONG?nowDepth.Bids[0].Price : nowDepth.Asks[0].Price) + (nowAccount.Balance - beginAccount.Balance); //总盈亏
table.b1 = nowAccount;//更新当前的账户信息
table.a5 = NowPositionInfo;
//更新入界面
}
var table = null;
function main() {
CancelPendingOrders();
_CInterval = 200;
InitAccount = exchange.GetAccount();//上次平仓后账户信息
beginAccount = InitAccount; //启动时账户信息
LoopInterval = Math.min(1, LoopInterval);
//清空
LogReset();
LogProfitReset();
chart = Chart(ChartCfg);
chart.reset();
Log('交易平台:', exchange.GetName(), InitAccount);
LogStatus("Ready...");
Log(InitAccount);
LoopInterval = Math.max(LoopInterval, 1);
//初始化表格
table = $.TableInit(2,7);
table.a0 = "初始账户:↓";
table.a1 = beginAccount;
table.b0 = "当前账户:↓";
table.a2 = "触发值A:↓";
table.b2 = "触发值B:↓";
table.a4 = "NowPositionInfo:↓";
//table.b4 = "stop";
//table.a5 = "Counter:";
var beginTime = 0;
while (true) {
beginTime = (new Date()).getTime();
onTick(exchange);
/* //ceshi
if(NowPositionInfo.floatProfit < -5){
Log("ticker:",_C(exchange.GetTicker),NowPositionInfo);
}
//ceshi
*/
Calculate();
$.UpdateLogStatus("loop used time:" + ((new Date()).getTime() - beginTime) + "ms");
Sleep(LoopInterval * 1000);
}
}
/*
0.是否当前K线允许交易 处理还有问题
1.触发平仓触发值,导致平仓,是否增加反转。
2. 计算浮动盈亏的函数
//改进
1、动态 触发值调整,根据波动率
2、参数 步长 、系数、试试 本K 重复开仓选项
3、双仓
*/
+16 -3
View File
@@ -11,15 +11,21 @@ exchange.GetRecords() ==> $.GetRecords(exchange, period)
其中period的单位为分钟。
回测K线周期应该尽可能选小(例如:回测近1个月内选1分钟,近5个月内选5分钟,等等),且period应是回测周期的倍数。
参数 默认值 描述
---- ----- ----------
tz 8 时区 (UTC+X)
*/
$.GetRecords = function (exchange, period) {
$.GetRecords = function (exchange, period) {
var prevT;
var rec1 = exchange.GetRecords();
if (!rec1) return null;
var recN = [];
var tmp = {Time: null, Open: null, High: null, Low: null, Close: null, Volume: 0};
for (var i = 0; i < rec1.length; i++) {
if (rec1[i].Time % (period*60000) === 0) {
if (!prevT || Math.floor((rec1[i].Time+tz*3600000) / (period*60000)) > prevT) {
prevT = Math.floor((rec1[i].Time+tz*3600000) / (period*60000));
tmp.Time = rec1[i].Time;
tmp.Open = rec1[i].Open;
tmp.High = rec1[i].High;
@@ -33,9 +39,16 @@ $.GetRecords = function (exchange, period) {
tmp.Close = rec1[i].Close;
tmp.Volume += rec1[i].Volume;
}
if ((i == rec1.length-1 || rec1[i+1].Time % (period*60000) === 0) && tmp.Time) {
if ((i == rec1.length-1 || Math.floor((rec1[i+1].Time+tz*3600000) / (period*60000)) > prevT) && tmp.Time) {
recN.push({Time: tmp.Time, Open: tmp.Open, High: tmp.High, Low: tmp.Low, Close: tmp.Close, Volume: tmp.Volume});
}
}
return recN;
};
function main() {
Log($.GetRecords(exchange,20*1440)); // 20日K线
Log(new Date($.GetRecords(exchange,1440)[0].Time).toString()); //测试日K线时间戳
Log(new Date($.GetRecords(exchange,1440)[1].Time).toString());
Log(new Date($.GetRecords(exchange,1440)[2].Time).toString());
}
+316
View File
@@ -0,0 +1,316 @@
/*
策略出处: https://www.botvs.com/strategy/6237
策略名称: 高频收割机一号
策略作者: Zero
策略描述:
代码本身就是很好的注释, 识货的拿走.
参数 默认值 描述
------------- --------------- ------
DicAmount 0.6,1.5,1.8,1.9 交易量
DicBuyOffset 1.5,2.5,4.5,8 买单距离
DicSellOffset 1,1.8,2.5,4 卖单距离
DicResetDiff 0.1,0.3,0.3,0.4 撤单差价
DicStep 9,12,17,25 增量步长
DicSleep 1,2,3,5 等待周期
SleepPeriod 3000 轮询周期
ChartPeriod 600 统计周期
IsEnableLog true 开启订单跟踪
按钮 默认值 描述
--------- ---------- ---------
开启/关闭订单跟踪 __button__ 开启/关闭订单跟踪
统计周期 3600 秒数
*/
var TAmount, TBuyOffset, TSellOffset, TResetDiff, TStep, TSleep, TLen;
var OrdersBuy = [];
var OrdersSell = [];
var InitAccount = null;
var __chart = null;
var __lastUpdate = 0;
function CancelPendingOrders() {
while (true) {
var orders = _C(exchange.GetOrders);
if (orders.length === 0) {
return;
}
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
if (i < (orders.length-1)) {
Sleep(500);
}
}
}
}
function str2array(s) {
var ret = [];
var arr = s.split(',');
for (var i = 0; i < arr.length; i++) {
ret.push(parseFloat(arr[i]));
}
return ret;
}
function parseOption() {
TAmount = str2array(DicAmount);
TBuyOffset = str2array(DicBuyOffset);
TSellOffset = str2array(DicSellOffset);
TResetDiff = str2array(DicResetDiff);
TStep = str2array(DicStep);
TSleep = str2array(DicSleep);
TLen = TAmount.length;
if ((TAmount.length !== TBuyOffset.length) ||
(TAmount.length !== TSellOffset.length) ||
(TAmount.length !== TStep.length) ||
(TAmount.length !== TSleep.length) ||
(TAmount.length !== TResetDiff.length) ) {
throw "参数有误, 表长度不一";
}
for (var i = 0; i < TLen; i++) {
OrdersBuy.push({Id: 0, Price: 0, Amount: 0});
OrdersSell.push({Id: 0, Price: 0, Amount: 0});
}
}
function getOrderPrice(books, limitAmount, prePrice, defRatio) {
var amount = 0;
for (var i = 0; i < books.length; i++) {
if (i > books.length - 3) {
return [books[1].Price * defRatio, false];
}
if (books[i].Price === prePrice) {
continue;
}
amount += books[i].Amount;
if (amount > limitAmount) {
return [books[i].Price, true];
}
}
}
function updateOrders() {
var ueseless = [];
var orders = _C(exchange.GetOrders);
// Update orders state, 1: Complete
for (var i = 0; i < TLen; i++) {
var found = false;
var j = 0;
if (OrdersBuy[i].Id > 0) {
for (j = 0; j < orders.length; j++) {
if (OrdersBuy[i].Id == orders[j].Id) {
found = true;
break;
}
}
if (!found) {
OrdersBuy[i] = {Id: 0, Price: 0};
}
}
found = false;
if (OrdersSell[i].Id > 0) {
for (j = 0; j < orders.length; j++) {
if (OrdersSell[i].Id == orders[j].Id) {
found = true;
break;
}
}
if (!found) {
OrdersSell[i] = {Id: 0, Price: 0};
}
}
}
// remove useless orders
while (true) {
var dropped = 0;
for (i = 0; i < orders.length; i++) {
var found = false;
for (j = 0; j < TLen; j++) {
if (OrdersBuy[j].Id == orders[i].Id || OrdersSell[j].Id == orders[i].Id) {
found = true;
}
}
if (!found) {
exchange.CancelOrder(orders[i].Id);
dropped++;
}
}
if (dropped === 0) {
break;
} else {
Sleep(1000);
orders = _C(exchange.GetOrders);
}
}
return true;
}
function onTick(pos) {
var depth = exchange.GetDepth();
if (!depth || depth.length < 2) {
return;
}
// recalc order price
var buys = [];
var sells = [];
for (var i = 0; i < TLen; i++) {
var buyPrice = getOrderPrice(depth.Bids, TAmount[i], OrdersBuy[i].Price, 0.99)[0] + (0.03 * Math.random());
var sellPrice = getOrderPrice(depth.Asks, TAmount[i], OrdersSell[i].Price, 1.01)[0] - (0.03 * Math.random());
var newSellPrice = sellPrice;
var newBuyPrice = buyPrice;
for(var newSellAmount = TAmount[i]; (newSellPrice - buyPrice) <= TSellOffset[i]; newSellAmount += TStep[i]) {
var retS = getOrderPrice(depth.Asks, newSellAmount, OrdersSell[i].Price, 1.01);
if (!retS[1]) {
break;
}
newSellPrice = retS[0] - (0.03 * Math.random());
}
for(var newBuyAmount = TAmount[i]; (sellPrice - newBuyPrice) <= TBuyOffset[i]; newBuyAmount += TStep[i]) {
var retB = getOrderPrice(depth.Bids, newBuyAmount, OrdersBuy[i].Price, 0.99);
if (!retB[1]) {
break;
}
newBuyPrice = retB[0] + (0.03 * Math.random());
}
buys.push(_N(newBuyPrice, 2));
sells.push(_N(newSellPrice, 2));
}
while (true) {
if (!updateOrders()) {
Sleep(1000);
}
var dropped = 0;
for (i = 0; i < TLen; i++) {
if (pos === 0 || (pos % TSleep[i] !== 0)) {
continue;
}
if (OrdersBuy[i].Id > 0 && Math.abs(buys[i] - OrdersBuy[i].Price) > TResetDiff[i]) {
//if (OrdersBuy[i].Id > 0 && (buys[i] - OrdersBuy[i].Price) > TResetDiff[i]) {
exchange.CancelOrder(OrdersBuy[i].Id);
dropped++;
}
if (OrdersSell[i].Id > 0 && Math.abs(sells[i] - OrdersSell[i].Price) > TResetDiff[i]) {
//if (OrdersSell[i].Id > 0 && (OrdersSell[i].Price - sells[i]) > TResetDiff[i]) {
exchange.CancelOrder(OrdersSell[i].Id);
dropped++;
}
}
if (dropped === 0) {
break;
} else {
Sleep(1000);
}
}
var account = _C(exchange.GetAccount);
var now = new Date().getTime();
if ((now - __lastUpdate) > (1000 * ChartPeriod)) {
__lastUpdate = now;
var btcPrice = depth.Bids[0].Price;
var net = _N(account.Balance + account.FrozenBalance + ((account.Stocks + account.FrozenStocks) * btcPrice));
__chart.add([0, [now, net]]);
__chart.add([1, [now, btcPrice]]);
}
var freeAmount = account.Stocks;
var freeBalance = account.Balance;
for (i = 0; i < TLen; i++) {
if (OrdersBuy[i].Id === 0) {
var orderAmount = Math.min(_N(freeBalance / buys[i]), TAmount[i]);
if (orderAmount >= 0.01) {
var orderId = exchange.Buy(buys[i], orderAmount);
if (orderId) {
OrdersBuy[i] = {Id: orderId, Price: buys[i], Amount: orderAmount};
}
}
freeBalance -= ((buys[i] + 1) * orderAmount);
}
if (OrdersSell[i].Id === 0 && freeAmount >= 0.01) {
var orderAmount = Math.min(freeAmount, TAmount[i]);
var orderId = exchange.Sell(sells[i], orderAmount);
if (orderId) {
OrdersSell[i] = {Id: orderId, Price: sells[i], Amount: orderAmount};
}
freeAmount -= orderAmount;
}
}
}
function onexit() {
CancelPendingOrders();
Log("exit");
}
function main() {
SetErrorFilter("订单不存在|10050|net");
exchange.IO("websocket")
__chart = Chart({
tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},
title : { text : '资产趋势'},
rangeSelector: {
buttons: [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}],
selected: 0,
inputEnabled: false
},
xAxis: { type: 'datetime'},
yAxis: [{ // Primary yAxis
labels: { format: '{value}元', style: { color: '#FF0000' } },
title: { text: '资产估值', style: { color: '#FF0000' } }
}, { title: { text: 'BTC单价', style: { color: '#4572A7' } },
labels: { format: '{value} 元', style: { color: '#4572A7' } },
opposite: false
}],
series : [{
name : '净产净值',
data : [],
tooltip: {
valueDecimals: 2
}
},{
name : 'BTC单价',
yAxis: 1,
data : [],
tooltip: {
valueDecimals: 2
}
}]
});
__chart.reset();
EnableLog(IsEnableLog);
Log("Switch to websocket => ", exchange.IO("websocket"));
CancelPendingOrders();
InitAccount = _C(exchange.GetAccount);
Log(InitAccount);
parseOption();
var allAmount = _.reduce(TAmount, function(memo, num){ return memo + num; }, 0);
var ticker = _C(exchange.GetTicker);
var ratio = (InitAccount.Balance + InitAccount.FrozenBalance + ((InitAccount.Stocks + InitAccount.FrozenStocks) * ticker.Buy)) / 2 / ticker.Buy / allAmount;
for (var i = 0; i < TAmount.length; i++) {
TAmount[i] = _N(TAmount[i] * ratio, 3);
}
Log("订单跟踪已经: " + (IsEnableLog ? "开启" : "关闭"), " 统计周期为", ChartPeriod, "秒, ", TAmount, "缩放比例:", _N(ratio));
for (var count = 0; ; count++) {
var cmd = GetCommand();
if (cmd == '开启/关闭订单跟踪') {
IsEnableLog = !IsEnableLog;
EnableLog(IsEnableLog);
Log("订单跟踪已经: " + (IsEnableLog ? "开启" : "关闭"));
} else if (cmd && cmd.indexOf('统计周期:') === 0) {
ChartPeriod = parseFloat(cmd.split(':')[1]);
Log("统计周期变更为", ChartPeriod, "秒");
}
onTick(count);
Sleep(SleepPeriod);
}
}