This commit is contained in:
Zero
2016-08-12 00:05:30 +08:00
parent 94b7ade7ee
commit b1534b4cec
4 changed files with 333 additions and 120 deletions
+3 -3
View File
@@ -4,10 +4,12 @@
> 开源策略列表
- [从第三方获取K线 (商品期货版) Rev. 160810](https://www.botvs.com/strategy/15498)
- [收益率统计](https://www.botvs.com/strategy/19329)
- [高频交易策略之 - Penny Jump](https://www.botvs.com/strategy/358)
- [CTP商品期货多品种海龟交易策略](https://www.botvs.com/strategy/17289)
- [商品期货交易类库](https://www.botvs.com/strategy/12961)
- [图表模板(增加状态栏表格功能)](https://www.botvs.com/strategy/16848)
- [收益率统计](https://www.botvs.com/strategy/19329)
- [从第三方网站获取K线 (0804更新)](https://www.botvs.com/strategy/12977)
- [不要怂就是干](https://www.botvs.com/strategy/18943)
- [入门模板之各个平台余额](https://www.botvs.com/strategy/48)
@@ -17,7 +19,6 @@
- [商品期货交易类库(增加下限价单功能)](https://www.botvs.com/strategy/14198)
- [获取OK期货实时限价](https://www.botvs.com/strategy/17028)
- [定期定额投资BTC盈利验证](https://www.botvs.com/strategy/16845)
- [从第三方获取K线 (商品期货版)](https://www.botvs.com/strategy/15498)
- [My-1-价值平均定投策略](https://www.botvs.com/strategy/8602)
- [记录净资产变动情况2.0](https://www.botvs.com/strategy/8916)
- [时间转换模板](https://www.botvs.com/strategy/14517)
@@ -78,7 +79,6 @@
- [取消所有订单](https://www.botvs.com/strategy/280)
- [新手入门之 - 下买单卖单](https://www.botvs.com/strategy/796)
- [短信通知接口测试](https://www.botvs.com/strategy/653)
- [高频交易策略之 - Penny Jump](https://www.botvs.com/strategy/358)
- [抢盘口做市策略 - 高频逼近型](https://www.botvs.com/strategy/348)
- [国外知名策略 Dual Thrust](https://www.botvs.com/strategy/153)
- [单平台均衡策略](https://www.botvs.com/strategy/345)
@@ -0,0 +1,184 @@
/*
策略出处: https://www.botvs.com/strategy/15498
策略名称: 从第三方获取K线 (商品期货版) Rev. 160810
策略作者: 数·狂
策略描述:
如果在策略开始时必须获取足够多的K线,使用本模板则可从第三方直接获得指定合约的历史K线数据。
Update 20160810:支持和讯数据源。(推荐!注意:K线周期只支持1、5、15、30<分钟>和1440<日线>)
Update 20160615:支持新浪财经数据源。
注意:
仅适用于实盘交易。
作者不保证第三方数据准确性和程序正确性,仅供学习参考。
*/
$.BTRecords = function(instrument, timeframe, size, includeLastBar) {
var info;
var record = [];
if (!size) size = 1;
if (!timeframe) timeframe = 1;
var fsize = size;
var now = new Date();
var to = Math.floor(now / 1000 / (timeframe * 60)) * (timeframe * 60);
var from = to - fsize * timeframe * 60;
do {
try {
info = JSON.parse(HttpQuery('https://www.botvs.com/chart/history?detail=true&symbol=' + instrument + '&resolution=' + timeframe + '&from=' + from + '&to=' + to));
if (info && info.records) {
info = info.records;
} else {
Log("获取K线时发生错误: 网络错误");
return null;
}
} catch (e) {
Log("获取K线时发生错误: 不完整的JSON数据");
return null;
}
fsize = fsize * 2;
from = to - fsize * timeframe * 60;
} while (info.length < size + (!includeLastBar));
for (var i = info.length - size - (!includeLastBar); i < info.length - (!includeLastBar); i++) {
record.push({
"Time": info[i][0] * 1000,
"Open": info[i][1],
"High": info[i][2],
"Low": info[i][3],
"Close": info[i][4],
"Volume": info[i][5]
});
}
return record;
};
$.SNRecords = function(instrument, timeframe, size, includeLastBar) {
var info;
var record = [];
// if (!size) size = 1;
if (!timeframe) timeframe = 1;
var pInst = instrument.toUpperCase();
if (pInst[pInst.length - 4] != '1') {
pInst = pInst.slice(0, pInst.length - 3) + '1' + pInst.slice(pInst.length - 3);
}
try {
info = JSON.parse(HttpQuery('http://stock2.finance.sina.com.cn/futures/api/json.php/IndexService.getInnerFuturesMiniKLine' + timeframe + 'm?symbol=' + pInst));
if (!info) {
Log("获取K线时发生错误: 网络错误或合约不存在");
return null;
}
} catch (e) {
Log("获取K线时发生错误: 不完整的JSON数据");
return null;
}
for (var i = (includeLastBar ? 0 : 1); i < size + (includeLastBar ? 0 : 1); i++) {
record.push({
"Time": Date.parse(info[i][0]) - timeframe * 60000 - 8 * 3600000,
"Open": Number(info[i][1]),
"High": Number(info[i][2]),
"Low": Number(info[i][3]),
"Close": Number(info[i][4]),
"Volume": Number(info[i][5])
});
}
return record.reverse();
};
var 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"]
}];
$.HXRecords = function(instrument, timeframe, size, includeLastBar) {
var info;
var record = [];
var now = new Date();
if (!size) size = 1;
if (!timeframe) timeframe = 1;
var pInst = instrument.toLowerCase();
if (pInst[pInst.length - 4] != '1') {
pInst = pInst.slice(0, pInst.length - 3) + '1' + pInst.slice(pInst.length - 3);
}
var filtered = instList.filter(function(xchg) {
return xchg.inst.indexOf(pInst.slice(0, pInst.length - 4)) != -1;
});
var xchg = filtered.length ? filtered[0].xchg : null;
if (!xchg) {
Log("获取K线时发生错误: 找不到合约");
return null;
}
var tf = (timeframe == 1 ? 0 : timeframe == 5 ? 1 : timeframe == 15 ? 2 : timeframe == 30 ? 3 : timeframe == 1440 ? 5 : -1);
if (tf < 0) {
Log("获取K线时发生错误: K线周期不正确");
return null;
}
var getTimestr = function(date) {
var yyyy = date.getFullYear();
var mm = date.getMonth() < 9 ? "0" + (date.getMonth() + 1) : (date.getMonth() + 1);
var dd = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
var hh = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
var min = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
var ss = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
return "".concat(yyyy).concat(mm).concat(dd).concat(hh).concat(min).concat(ss);
};
var getDate = function(timestr) {
var str = timestr.toString();
var y = str.substr(0, 4);
var mo = str.substr(4, 2) - 1;
var d = str.substr(6, 2);
var h = str.substr(8, 2);
var min = str.substr(10, 2);
var sec = str.substr(12, 2);
return new Date(y, mo, d, h, min, sec);
};
var timestr = getTimestr(new Date(now.getFullYear(), now.getMonth(), now.getDate()+1));
try {
var resp = HttpQuery('http://webftcn.hermes.hexun.com/shf/kline?code=' + xchg + pInst + '&start=' + timestr + '&number=-' + size + '&type=' + tf);
info = JSON.parse(resp.slice(1, resp.length - 2));
if (info && info.Data) {
info = info.Data;
} else {
Log("获取K线时发生错误: 网络错误");
return null;
}
} catch (e) {
Log("获取K线时发生错误: 不完整的JSON数据");
return null;
}
for (var i = 0; i < info[0].length - (!includeLastBar); i++) {
record.push({
"Time": getDate(info[0][i][0]).valueOf(),
"Open": info[0][i][2] / info[4],
"High": info[0][i][4] / info[4],
"Low": info[0][i][5] / info[4],
"Close": info[0][i][3] / info[4],
"Volume": info[0][i][6]
});
}
return record;
};
function main() {
Log(exchange.GetName());
var rec = $.BTRecords('rb1610', 5, 100); // 从BotVS获取螺纹钢1610的5分钟K线, 100条, 不含最后一条Bar
if (rec) Log(rec.length, rec[rec.length - 1]);
rec = $.SNRecords('MA609', 60, 100, true); // 从新浪财经获取甲醇609的1小时K线, 100条, 含最后一条Bar
if (rec) Log(rec.length, rec[rec.length - 1]);
rec = $.HXRecords('i1701', 15, 100, true); // 从和讯获取铁矿石1701的15分钟K线, 100条, 含最后一条Bar
if (rec) Log(rec.length, rec[rec.length - 1]);
rec = $.BTRecords('i1701', 15, 100, true); // BotVS数据对比
if (rec) Log(rec.length, rec[rec.length - 1]);
rec = $.SNRecords('i1701', 15, 100, true); // 新浪财经数据对比
if (rec) Log(rec.length, rec[rec.length - 1]);
}
+10 -1
View File
@@ -30,11 +30,20 @@ function main() {
上30日: 收200.12元(1.565%),月化1.567%,年化19.076%,回撤1.521%
总: 收4554.11元(45.541%),最大回撤3.251%,统计时间74天23小时
参数 默认值 描述
------------- ----- ---------------------
SYS_LOGPROFIT true 是否同时记录到系统自带的LogProfit
*/
$.LogProfit = function(profit) {
var args = Array.prototype.slice.call(arguments);
LogProfit.apply(this, args);
if (SYS_LOGPROFIT) {
LogProfit.apply(this, args);
} else {
args.unshift('收益');
Log.apply(this,args);
}
var _history = $.GetAllProfit();
_history.push([ Math.floor(new Date().getTime()/1000), profit]);
+136 -116
View File
@@ -4,142 +4,162 @@
策略作者: Zero
策略描述:
Penny jump, 请自行百度
今天假设有一个笨笨的大型机构投资人(共同基金,银行,退休基金….),他想要买进一只股票,但又不想挂市价买进,所以就在市场里面挂了一张要买进的大单。这时候所有市场里面的人都会看的到limit order book里面有人挂进了大单准备要买进这只股票。
假设市场本来的order book是200 | $1.01 x $1.03 | 200,然后突然这个笨笨的机构投资人进来挂了一张3000股$1.01 的买单,这时候order book会变成3,200 | $1.01 x $1.03 | 200。而我们通常称这个笨笨的机构投资人为”大象,elephant”,而高频交易者知道$1.01的价位有支撑的买单,所以便会把他们的bid price提高1美分到$1.02,而这样的策略就叫做Penny Jump。因为高频交易者知道往下一档的地方,有一只”大象”在支撑着。所以如果价格往上涨到$1.03 x $1.05的话,他就可以马上赚取$0.01的利润。
如果高频交易商买进这只股票之后,就算价格没有往上涨的话,因为下面有一只大象在支撑着,所以他也可以很快的反手用$1.01的价位卖给这只大象。
对于高频交易商来说,他们获利的方法其实也很简单,就是由市场上的微结构(microstrucutre)来推测交易对手的意图,然后抢先他人一步建立部位。然后在短时间之内赚取微小利润,再迅速离开市场。
对于这只大象来说,他因为在市场里面挂了一张巨量的买单,所以暴露了他的交易意图,自然就变成高频交易者猎杀的目标。
而在现实的股票交易世界里面,应该很少有这种笨笨的机构投资人会明目张胆的在市场上挂出巨量的买单(或卖单)。反而常见的是大型机构投资人,想要出脱一只股票,所以故意挂出巨量的买单来制造假象,来吸引高频交易者进场来推升股价,然后再一股脑的把货倒出来,而这就是交易世界里面的尔虞我 诈。
对于高频交易商来说,一旦这个策略被看穿而被”对作,Gaming”,则他们就又会回头来”反对作”,发展策略来吃这种机构投资人”对作”的豆腐。
参数 默认值 描述
------------ ----- ----------
Interval 2000 出错重试间隔(毫秒)
LoopInterval true 轮询间隔(秒)
SlidePrice 0.1 滑点
Lot 0.2 手数
DisableLog false 关闭订单跟踪
参数 默认值 描述
-------------- ----- ----------
Interval 2000 出错重试间隔(毫秒)
Lot 0.01 手数
DisableLog false 关闭订单跟踪
ElephantAmount 10 大象级别(BTC)
ElephantSpace 0.2 大象距离(元)
LockCount true 大象确定次数
PennyTick 0.1 跳
WaitInterval 5000 买单超时(毫秒)
CheckInterval 300 快速检测间隔(毫秒)
ProfitTick 5 利润跳数
STTick true 止损跳数
*/
function adjustFloat(v) {
return Math.floor(v*1000)/1000;
}
function GetOrders() {
var orders = null;
while (!(orders = exchange.GetOrders())) {
Sleep(Interval);
}
return orders;
}
function CancelPendingOrders(orderType) {
while (true) {
var orders = GetOrders();
var count = 0;
if (typeof(orderType) != 'undefined') {
for (var i = 0; i < orders.length; i++) {
if (orders[i].Type == orderType) {
count++;
}
}
} else {
count = orders.length;
}
if (count == 0) {
return;
}
for (var j = 0; j < orders.length; j++) {
if (typeof(orderType) == 'undefined' || (orderType == orders[j].Type)) {
exchange.CancelOrder(orders[j].Id, orders[j]);
if (j < (orders.length-1)) {
Sleep(Interval);
}
}
}
}
}
function GetAccount() {
var account;
while (!(account = exchange.GetAccount())) {
Sleep(Interval);
}
return account;
}
function GetTicker(e) {
if (typeof(e) == 'undefined') {
e = exchange;
}
var ticker;
while (!(ticker = e.GetTicker())) {
Sleep(Interval);
}
return ticker;
}
function updateProfit(accountInit, accountNow, ticker) {
var netNow = accountNow.Balance + accountNow.FrozenBalance + ((accountNow.Stocks + accountNow.FrozenStocks) * ticker.Buy);
var netInit = accountInit.Balance + accountInit.FrozenBalance + ((accountInit.Stocks + accountInit.FrozenStocks) * ticker.Buy);
LogProfit(adjustFloat(netNow - netInit), accountNow);
}
var Counter = {
i: 0,
w: 0,
f: 0
};
// Variables
var InitAccount = null;
function onTick() {
var ticker = GetTicker();
var dealAmount = 0;
for (var i = 0; i < 10; i++) {
var account = GetAccount();
dealAmount = adjustFloat(account.Stocks - InitAccount.Stocks);
if (dealAmount >= exchange.GetMinStock()) {
break;
}
var buyPrice = ticker.Buy + SlidePrice;
var amountBuy = Math.min(adjustFloat(account.Balance / buyPrice), Lot);
if (amountBuy < exchange.GetMinStock()) {
throw "没有钱买币了...";
}
exchange.Buy(buyPrice, amountBuy);
Sleep(1000);
CancelPendingOrders();
}
if (dealAmount < exchange.GetMinStock()) {
return;
}
var update = false;
var count = 0;
function CancelAll() {
while (true) {
var sellAmount = adjustFloat(GetAccount().Stocks - InitAccount.Stocks);
if (sellAmount < exchange.GetMinStock()) {
var orders = _C(exchange.GetOrders);
if (orders.length == 0) {
break;
}
exchange.Sell(ticker.Buy + (2 * SlidePrice), sellAmount);
update = true;
if (count == 0) {
Sleep(10000);
} else {
Sleep(1000);
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
}
CancelPendingOrders();
ticker = GetTicker();
count++;
}
if (update) {
updateProfit(InitAccount, GetAccount(), GetTicker());
Sleep(Interval);
}
}
function updateStatus(msg) {
LogStatus("调戏次数:", Counter.i, "成功:", Counter.w, "失败:", Counter.f, "\n"+msg+"#0000ff\n"+new Date());
}
function main() {
if (DisableLog) {
EnableLog(false);
}
InitAccount = GetAccount();
CancelAll();
InitAccount = _C(exchange.GetAccount);
Log(InitAccount);
LoopInterval = Math.max(LoopInterval, 1);
Lot = Math.max(exchange.GetMinStock(), Lot);
var i = 0;
var locks = 0;
while (true) {
onTick();
Sleep(LoopInterval * 1000);
Sleep(Interval);
var depth = _C(exchange.GetDepth);
if (depth.Asks.length === 0 || depth.Bids.length === 0) {
continue;
}
updateStatus("搜索大象中.... 买一: " + depth.Bids[0].Price + ",  卖一:" + depth.Asks[0].Price + ", 锁定次数: " + locks);
var askPrice = 0;
for (i = 0; i < depth.Asks.length; i++) {
if (depth.Asks[i].Amount >= Lot) {
askPrice = depth.Asks[i].Price;
break;
}
}
if (askPrice === 0) {
continue;
}
var elephant = null;
// skip Bids[0]
for (i = 1; i < depth.Bids.length; i++) {
if ((askPrice - depth.Bids[i].Price) > ElephantSpace) {
break;
}
if (depth.Bids[i].Amount >= ElephantAmount) {
elephant = depth.Bids[i];
break;
}
}
if (!elephant) {
locks = 0;
continue;
}
locks++;
if (locks < LockCount) {
continue;
}
locks = 0;
updateStatus("调戏大象中....大象在第" + i + "档, " + JSON.stringify(elephant));
exchange.Buy(elephant.Price + PennyTick, Lot, "Bids[" + i + "]", elephant);
var ts = new Date().getTime();
while (true) {
Sleep(CheckInterval);
var orders = _C(exchange.GetOrders);
if (orders.length == 0) {
break;
}
if ((new Date().getTime() - ts) > WaitInterval) {
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
}
}
}
var account = _C(exchange.GetAccount);
var opAmount = _N(account.Stocks - InitAccount.Stocks);
if (opAmount < 0.001) {
Counter.f++;
Counter.i++;
continue;
}
updateStatus("买单得手: " + opAmount +", 开始出手...");
exchange.Sell(elephant.Price + (PennyTick * ProfitTick), opAmount);
var success = true;
while (true) {
var depth = _C(exchange.GetDepth);
if (depth.Bids.length > 0 && depth.Bids[0].Price <= (elephant.Price-(STTick*PennyTick))) {
success = false;
updateStatus("没有得手, 开始止损, 当前买一: " + depth.Bids[0].Price);
CancelAll();
account = _C(exchange.GetAccount);
var opAmount = _N(account.Stocks - InitAccount.Stocks);
if (opAmount < 0.001) {
break;
}
exchange.Sell(depth.Bids[0].Price, opAmount);
}
var orders = _C(exchange.GetOrders);
if (orders.length === 0) {
break;
}
Sleep(CheckInterval);
}
if (success) {
Counter.w++;
} else {
Counter.f++;
}
Counter.i++;
var account = _C(exchange.GetAccount);
LogProfit(account.Balance - InitAccount.Balance, account);
}
}