Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
root committed Feb 7, 2023
1 parent 9e5ffa1 commit a6c574f
Show file tree
Hide file tree
Showing 15 changed files with 1,211 additions and 239 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

> 策略名称
搬运FMZ教程-JavaScript速成手册
FMZ教程-JavaScript速成手册

> 策略作者
Expand Down Expand Up @@ -378,4 +378,4 @@ https://www.fmz.com/strategy/395725

> 更新时间
2023-01-05 17:04:51
2023-01-16 09:43:09
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

> 策略名称
搬运FMZ教程-Python速成手册
FMZ教程-Python速成手册

> 策略作者
Expand Down Expand Up @@ -465,4 +465,4 @@ https://www.fmz.com/strategy/395727

> 更新时间
2023-01-05 17:04:56
2023-01-16 09:43:03
200 changes: 200 additions & 0 deletions HFT高频订单流因子.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@

> 策略名称
HFT高频订单流因子

> 策略作者
发明者量化

> 策略描述

一个入门级订单流高频alpha因子, 可以做为市商策略的最优买卖定价距离参考, 信号归一为[-1, 1], 趋向1表示买方市场,趋向-1则是卖方市场, 策略会实时绘制因子值与最后成交价
策略使用OKX与币安期货websocket接口接收计算, 下图是指标效果, 可以看出有一定的有效性, 公开给高频入门的量化爱好者

![IMG](https://www.fmz.com/upload/asset/a89668d3b0189c8902.png)



> 策略参数


|参数|默认值|描述|
|----|----|----|
|QSize|100|QSize|


> 源码 (javascript)
``` javascript
let _chart = Chart({
subtitle: {
text: "Market Status",
},
yAxis: [{
height: "60%",
lineWidth: 1,
title: {
text: 'Close',
},
opposite: true,
labels: {
align: "right",
x: -3,
}
}, {
title: {
text: 'Alpha',
},
top: "60%",
height: "20%",
offset: 0,
lineWidth: 1
}, {
title: {
text: 'Vol',
},
top: "80%",
height: "20%",
offset: 0,
lineWidth: 1
}],

series: [{
name: 'Last',
lineWidth: 1,
data: [],
id: 'primary',
tooltip: {
xDateFormat: '%Y-%m-%d %H:%M:%S'
},
yAxis: 0
}, {
type: 'column',
lineWidth: 2,
name: 'Alpha',
data: [],
yAxis: 1,
color: 'green',
zones: [{
value: 0,
color: 'red'
}]
}, {
lineWidth: 1,
type: 'area',
color: '#257ed4',
name: 'Vol',
data: [],
yAxis: 2
}],
})

function calc_alpha(trades) {
let tick_sell_vol = 0
let tick_buy_vol = 0
let last_buy_vol = 0
let last_sell_vol = 0
let rightPos = Math.ceil(trades.length * 0.382)
trades.forEach(function(trade, idx) {
if (trade.side == 'buy') {
if (idx >= rightPos) {
last_buy_vol += trade.qty
}
tick_buy_vol += trade.qty
} else {
if (idx >= rightPos) {
last_sell_vol += trade.qty
}
tick_sell_vol += trade.qty
}
})

let tanh = function(x) {
// return [-1, 1]
return (Math.exp(x) - Math.exp(-x)) / (Math.exp(x) + Math.exp(-x))
}

let positive_ratio = last_buy_vol / tick_sell_vol
let negative_ratio = last_sell_vol / tick_buy_vol
let trade_ratio = 0
if (positive_ratio > negative_ratio) {
trade_ratio = tanh(positive_ratio)
} else {
trade_ratio = tanh(-negative_ratio)
}
return _N(trade_ratio, 3)
}

let _trades = []
let _vol = 0

function onTick(ctx, event) {
if (event.trades) {
event.trades.forEach(function(trade) {
_vol += trade.qty
_trades.push(trade)
if (_trades.length > QSize) {
_trades.shift()
}
})
if (_trades.length >= QSize) {
let val = calc_alpha(_trades)
_chart.add(0, [event.ts, _trades[_trades.length-1].price])
_chart.add(1, [event.ts, val])
_chart.add(2, [event.ts, _vol])
_vol = 0
}
}
}

function main() {
let ctName = "swap"
_chart.reset()
let ctx = $.NewWSS(exchange, function(ws, e) {
let msg = null
if (e.GetName() == 'Futures_OKCoin') {
msg = {
op: "subscribe",
args: []
}
let instId = e.SetContractType(ctName).InstrumentID
msg.args.push({
channel: "books5",
instId: instId
})
msg.args.push({
channel: "trades",
instId: instId
})
} else {
msg = {
method: "SUBSCRIBE",
params: [],
id: "1"
}
let symbol = e.GetCurrency().replace('_', '').toLowerCase()
msg.params.push(symbol + "@aggTrade")
msg.params.push(symbol + "@depth20@100ms")
}
ws.write(JSON.stringify(msg))
Log("subscribe", msg, "channel")
LogStatus("Ready")
}, onTick, false)

while (true) {
ctx.poll()
EventLoop(1000)
}
}
```

> 策略出处
https://www.fmz.com/strategy/392784

> 更新时间
2023-02-01 19:43:36
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ OKX&Binance Websocket高频交易模板 (多品种)||OKEX & Binance Websocket Hi
[trans]
实现功能:
1. 公共流订阅, trades及深度合成
2. 私有流订阅, 维护本地委托单与仓位以及余额信息
3. 维护取消订单超时状态, 支持OKX的amendOrders修改订单
4. 支持多个品种, 方便高频策略以最低的延迟同时操作多个市场
5. 添加函数 EventLoop(需要最新托管者支持), 此函数可以在多个websocket连接的情况下, 等待任意websocket数据返回, 避免轮询
6. 支持OKX与Binance期货与Binance的现货与现货杠杆交易, OKX的现货暂未加入支持, 感兴趣的可以自己更改一下
7. OKX的私有流订阅需要Key与密码已经做为参数写在模板里
8. 自动处理断线重连等一些基本的网络功能
9. 支持私有流订单成交取消回报的事件回调
10. 统一两个交易所的下单逻辑, 具体可以看模板源码或者例子
11. 支持同时订阅多个交易所的websocket接口
12. 订单的报单修改以及删除可以批量做为任务返回, 会自动处理交易任务
* 公共流订阅, trades及深度合成
* 私有流订阅, 维护本地委托单与仓位以及余额信息
* 维护取消订单超时状态, 支持OKX的amendOrders修改订单
* 支持多个品种, 方便高频策略以最低的延迟同时操作多个市场
* 添加函数 EventLoop(需要最新托管者支持), 此函数可以在多个websocket连接的情况下, 等待任意websocket数据返回, 避免轮询
* 支持OKX与Binance期货与Binance的现货与现货杠杆交易, OKX的现货暂未加入支持, 感兴趣的可以自己更改一下
* OKX的私有流订阅需要Key与密码已经做为参数写在模板里
* 自动处理断线重连等一些基本的网络功能
* 支持私有流订单成交取消回报的事件回调
* 统一两个交易所的下单逻辑, 具体可以看模板源码或者例子
* 支持同时订阅多个交易所的websocket接口
* 订单的报单修改以及删除可以批量做为任务返回, 会自动处理交易任务

高频下单的时候,交易所返回的定单会不及时(private通道),但这时侯行情可能已经变化,我们需要本地维护一个订单状态, 策略已经实现,
模板会自动识别是OKX还是Binance, 下面是一个简单的例子, 强烈建议阅读源码,这样能更深层次的定制你自己的功能
Expand Down Expand Up @@ -132,7 +132,7 @@ function main() {
while (true) {
ctx.poll()
__syscall("TSocket_WaitAny", 1000)
EventLoop(1000)
}
}
```
Expand Down Expand Up @@ -539,6 +539,11 @@ function NewOKXWebSocketPrivate(ctx, verbose) {
}

self.poll = function(timeout) {

if (AccessKey.length == 0) {
return
}

let ts = new Date().getTime()
if (self.lastPing == 0) {
self.lastPing = ts
Expand Down Expand Up @@ -610,11 +615,13 @@ function NewOKXWebSocketPublic(e, onLogin, onTick, verbose) {

let self = {
e: e,
key: e.GetName() + '/' + e.GetCurrency(),
quoteCurrency: e.GetQuoteCurrency(),
name: e.GetName(),
verbose: verbose,
isFutures: e.GetName().indexOf("Futures_") == 0,
ws: null,
cache: {},
channles: [],
depthCount: 0,
depthConsumed: 0,
Expand All @@ -623,7 +630,6 @@ function NewOKXWebSocketPublic(e, onLogin, onTick, verbose) {
asks: {},
bids: {}
},
trades: [],
lastMarket: 0
}
self.wsPrivate = NewOKXWebSocketPrivate(self, verbose)
Expand Down Expand Up @@ -655,7 +661,7 @@ function NewOKXWebSocketPublic(e, onLogin, onTick, verbose) {
} else if (obj.event == 'login') {
self.channles = []
if (typeof(onLogin) === 'function') {
onLogin(self.ws)
onLogin(self.ws, self.e)
}
} else {
self.lastMarket = new Date().getTime();
Expand Down Expand Up @@ -786,17 +792,23 @@ function NewOKXWebSocketPublic(e, onLogin, onTick, verbose) {
if (!self.ws) {
return
}
let tsStr = (new Date().getTime() / 1000).toString()
let authMsg = {
"op": "login",
"args": [{
"apiKey": AccessKey,
"passphrase": Passphrase,
"timestamp": tsStr,
"sign": self.e.HMAC("sha256", "base64", tsStr + "GET" + "/users/self/verify", "{{secretkey}}")
}]
if (AccessKey.length == 0) {
if (typeof(onLogin) === 'function') {
onLogin(self.ws, self.e)
}
} else {
let tsStr = (new Date().getTime() / 1000).toString()
let authMsg = {
"op": "login",
"args": [{
"apiKey": AccessKey,
"passphrase": Passphrase,
"timestamp": tsStr,
"sign": self.e.HMAC("sha256", "base64", tsStr + "GET" + "/users/self/verify", "{{secretkey}}")
}]
}
self.ws.write(JSON.stringify(authMsg))
}
self.ws.write(JSON.stringify(authMsg))
}
if (!self.ws) {
return
Expand Down Expand Up @@ -1286,16 +1298,17 @@ function NewBinanceSocketPrivate(ctx, verbose) {
function NewBinanceWebSocketPublic(e, onLogin, onTick, verbose) {
let self = {
e: e,
key: e.GetName() + '/' + e.GetCurrency(),
quoteCurrency: e.GetQuoteCurrency(),
name: e.GetName(),
isFutures: e.GetName().indexOf("Futures_") == 0,
verbose: verbose,
ws: null,
cache: {},
depthCount: 0,
depthConsumed: 0,
lastPing: 0,
isReadyDic: {},
trades: []
isReadyDic: {}
}
self.base = self.isFutures ? "wss://fstream.binance.com/ws" : "wss://stream.binance.com/ws"

Expand Down Expand Up @@ -1407,7 +1420,7 @@ function NewBinanceWebSocketPublic(e, onLogin, onTick, verbose) {
Log("Dial: ", self.base)
self.ws = Dial(self.base)
if (self.ws) {
onLogin(self.ws)
onLogin(self.ws, self.e)
}
}
if (!self.ws) {
Expand Down Expand Up @@ -1560,4 +1573,4 @@ https://www.fmz.com/strategy/395045

> 更新时间
2023-01-11 16:16:25
2023-02-02 20:12:19
Loading

0 comments on commit a6c574f

Please sign in to comment.