This commit is contained in:
Zero
2020-04-17 16:37:51 +08:00
parent 4cd7674c0e
commit 7fef01d8cd
29 changed files with 3189 additions and 1941 deletions
@@ -1,329 +0,0 @@
> 策略名称
FMEX[空头]趋势挖矿策略(随机网格排序)
> 策略作者
古力十段
> 策略描述
FMex排序挖矿空头版本代码使用说明。(注意api地址)(加强版-增加仓位管理-增加时间设定,调整单量方向等-购买联系微信:ying5737)
(预计日跌幅1%以上,赚币赚矿,反之亏损明显)
保证金市场风险巨大,你可能随时面临100%损失。或有不明bug100%损失,概不负责。
原理:盘口下单随机成交/
先持仓SHORT100u。//注意:先手动持仓SHORT100u。
- 检测现有订单是否超过界限,如果超过了就立马取消该订单/
- 检测是否成交形成了仓位,如果大于仓位xxu,则减仓到既定仓位以下/
几种情况:
全局挂单:为区别市商策略,特定定义远端排序为挂单,参数为买(35u)单量卖(35u)左右。参数可调。
市商:
最大多头持仓100u,若大于该仓位,约每6s减20u仓位,直到小于100u.
最大空头持仓1000u,若大于该仓位,约每6s减200u仓位,直到小于100u.
大于1u多仓启动减多仓策略,挂单为short:卖3卖4卖5(各30u单量)
大于800u空仓,启动减空仓策略,挂单为long:买2买3买4(各30u单量)
正常持仓,SHORT 卖2卖3卖4
//参数中的备注描述,仅供参考,另可加挡位
风险自负/参数可调,购买加强版联系微信:ying5737
> 策略参数
|参数|默认值|描述|
|----|----|----|
|Url|https://api.fmex.com|交易所api地址|
|g_minPercent|0.05|挂单:挖矿的下限,离最新价的百分比,如果是 1% 则填写 1|
|g_maxPercent|0.05|挂单:挖矿的上限,离最新价的百分比,如果是 1% 则填写 1|
|g_perAmount|35|挂单:每个订单量多少张,最多只能挂50个订单|
|g_kongtouAmount|35|挂单:|
|g_maxHoldingLong|100|挂单:多单最大持仓量|
|g_maxHoldingShort|1000|挂单:空单最大持仓量|
|sp_jiancangAmount|true|市商/排序:减仓多仓|
|sp_jiacangAmount|true|市商/排序:增加多仓|
|sp_kongtouAmount|30|市商/排序: 空头数|
|sp_perAmount|30|市商/排序:单个订单大小|
|mainIntervel|false|Intervel|
|Intervel|false|Intervel0|
|sp_baseAmountLong|true|多仓|
|sp_baseAmountShort|800|空仓|
> 源码 (javascript)
``` javascript
exchange.IO("base", Url)//保证金市场风险巨大,你可能随时面临100%损失。或有不明bug100%损失,概不负责。
//实盘地址:https://api.fmex.com 测试网https://api.testnet.fmex.com//注意:先持仓short100u。
var ordersInfo = {//(加强版-增加仓位管理-增加时间设定-调整单量方向等-价格美丽/购买联系微信:ying5737)
buyId: 0,
buyPrice: 0,
sellId: 0,
sellPrice: 0,
minPrice: 0,
maxPrice: 0
}
var depthInfo = {//注意:先手动持仓short100u。
asks: [],
bids: []
}
function getTicker(symbol) {
url = "/v2/market/ticker/" + symbol;
data = exchange.IO("api", "GET", url);
return data.data;
}
function getAccounts() {
data = exchange.IO("api", "GET", "/v3/contracts/accounts")
return data.data;
}
function createOrderPrice(body) {
parameter = "symbol=" + body.symbol + "&type=" + body.type + "&direction=" + body.direction + "&post_only=" + body.post_only + "&price=" + body.price + "&quantity=" + body.quantity;
resultData = exchange.IO("api", "POST", "/v3/contracts/orders", parameter)
return resultData;
}
function createOrder(body) {
parameter = "symbol=" + body.symbol + "&type=" + body.type + "&direction=" + body.direction + "&quantity=" + body.quantity;
resultData = exchange.IO("api", "POST", "/v3/contracts/orders", parameter)
return resultData;
}
function getOrders() {
resultData = exchange.IO("api", "GET", "/v3/contracts/orders/open");
return resultData.data
}
function cancelOrder(id) {
resultData = exchange.IO("api", "POST", "/v3/contracts/orders/" + id + "/cancel");
return resultData;
}
function getPosition() {
resultData = exchange.IO("api", "GET", "/v3/broker/auth/contracts/positions");
return resultData.data;
}
function getMatches(id) {
resultData = exchange.IO("api", "GET", "/v3/contracts/orders/" + id + "/matches");
return resultData.data;
}
function getCandles(resolution, symbol) {
resultData = exchange.IO("api", "GET", "/v2/market/candles/" + resolution + "/" + symbol);
return resultData.data;
}
function cleanOrders(lastPrice) {
ordersInfo = getOrders();
orders = ordersInfo.results;
for (var i = 0; i < orders.length; i++) {
diffPercent = Math.abs(lastPrice - orders[i].price) / lastPrice * 100
if (diffPercent < g_minPercent || diffPercent > g_maxPercent) {
orderInfo = cancelOrder(orders[i].id);
Log("挂单取消订单:");
}
}
}
function getToOrderPrice(basePrice, direct) {
return parseInt(basePrice * (direct * (g_minPercent + Math.random() * (g_maxPercent - g_minPercent)) / 100 + 1))
}
function cleanPosition() {
res = getPosition();
res.results.forEach(function(it) {
if (it.symbol == 'BTCUSD_P') {
if (it.quantity) {
if (it.quantity > g_maxHoldingLong && it.direction.toUpperCase() == 'LONG') {
data = createOrder({
symbol: "BTCUSD_P",
type: "MARKET",
direction: it.direction.toUpperCase() == 'LONG' ? "SHORT" : "LONG",
quantity: 20,
})
Log("平仓:");
}
if (it.quantity > g_maxHoldingShort && it.direction.toUpperCase() == 'SHORT') {
data = createOrder({
symbol: "BTCUSD_P",
type: "MARKET",
direction: it.direction.toUpperCase() == 'LONG' ? "SHORT" : "LONG",
quantity: 20,
})
Log("平仓:");
}
}
}
});
}
function guadan() {
tickerInfo = getTicker('BTCUSD_P');
ticker = tickerInfo.ticker;
var lastPrice = ticker[0];
Log("lastPrice: "+lastPrice);
buyPrice = getToOrderPrice(lastPrice, -1);
sellPrice = getToOrderPrice(lastPrice, 1);
LongOrderInfo = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "LONG",
post_only: true,
price: buyPrice,
quantity: g_perAmount,
})
Log("挂单LONG:" );
shortOrderInfo = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: sellPrice,
quantity: g_kongtouAmount,
})
Log("挂单SHORT:" );
cleanOrders(lastPrice)
cleanPosition();
}
function shishang() {
Log("市商/排序挖矿**********************************");
tickerInfo = getTicker('BTCUSD_P');
ticker = tickerInfo.ticker;
Log("市商/排序挖矿ticker:");
lastPrice = ticker[0]
buyPrice = ticker[2]
sellPrice = ticker[4]
Log("lastPrice:"+lastPrice+":buyPrice:"+buyPrice+":sellPrice:" + sellPrice);
if (lastPrice == buyPrice) {
sellPrice = (buyPrice + 0.5).toFixed(1)
}
if (lastPrice == sellPrice) {
buyPrice = (sellPrice - 0.5).toFixed(1)
}
Log("buyPrice:"+buyPrice+":sellPrice:" + sellPrice);
// const LastK7 = k[7]; // 最近第九根
res = getPosition();
Log("市商/排序挖矿Position:" + JSON.stringify(res));
res.results.forEach(function(it) {
if (it.symbol == 'BTCUSD_P') {
if (it.quantity) {
if (it.quantity > sp_baseAmountLong && it.direction.toUpperCase() == 'LONG') {
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: lastPrice + 1.5,
quantity: sp_perAmount,
})
Log("排序10:" );
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: lastPrice + 2,
quantity: sp_perAmount,
})
Log("排序9:" );
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: lastPrice + 2.5,
quantity: sp_perAmount,
})
Log("排序8:");
} else if (it.quantity > sp_baseAmountShort && it.direction.toUpperCase() == 'SHORT') {
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "LONG",
post_only: true,
price: lastPrice - 0.5,
quantity: sp_perAmount,
})
Log("市商/排序-2:");
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "LONG",
post_only: true,
price: lastPrice - 1,
quantity: sp_perAmount,
})
Log("市商/排序-3:" );
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "LONG",
post_only: true,
price: lastPrice - 1.5,
quantity: sp_perAmount,
})
Log("市商/排序-4:" );
} else {
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: lastPrice - 1,
quantity: sp_perAmount,
})
Log("市商-3:" );
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: lastPrice - 1.5,
quantity: sp_perAmount,
})
Log("市商-4:" );
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: lastPrice - 2,
quantity: sp_perAmount,
})
Log("市商-5:");
}
}
}
})
}
/********************END 市商/排序挖矿***************************************************************************************************/
function main() {
while(true){
guadan();
Sleep(Intervel * 1000)
shishang()
Sleep(mainIntervel * 1000)
}
}//FMex排序挖矿多头版本代码使用说明。(注意api地址)(加强版-增加仓位管理-增加时间设定等-购买联系微信:ying5737)
```
> 策略出处
https://www.fmz.com/strategy/178417
> 更新时间
2019-12-21 07:34:12
@@ -1,359 +0,0 @@
> 策略名称
FMEX挖矿策略(排序)btc均衡或【震荡版】
> 策略作者
古力十段
> 策略描述
FMex排序挖矿均衡代码使用说明。(注意api地址)(加强版-增加仓位管理-增加时间设定,调整单量,方向等-购买联系微信:ying5737)
保证金市场风险巨大,你可能随时面临100%损失。或有不明bug100%损失,概不负责。
原理:盘口下单随机成交/
//注意:先手动持仓long1u。
- 检测现有订单是否超过界限,如果超过了就立马取消该订单/
- 检测是否成交形成了仓位,如果大于仓位xxu,则减仓到既定仓位以下/
几种情况:
全局挂单:为区别市商策略,特定定义远端排序为挂单,参数为买(35u)单量卖(35u)左右。参数可调。
市商:
最大多头持仓700u,若大于该仓位,约每6s减20u仓位,直到小于700u.
最大空头持仓700u,若大于该仓位,约每6s减20u仓位,直到小于700u.
大于500u多仓启动减多仓策略,挂单为short:卖3卖4卖5(各30u单量)
大于500u空仓,启动减空仓策略,挂单为long:买2买3买4(各30u单量)
正常持仓,SHORT 卖7卖8卖9 long买4买7买8
//可其他账户持仓对冲,对行情有把握后,亦可以单独开
//参数中的备注描述,仅供参考,另可加挡位
风险自负/参数可调,购买加强版联系微信:ying5737
> 策略参数
|参数|默认值|描述|
|----|----|----|
|Url|https://api.fmex.com|交易所api地址|
|g_minPercent|0.05|挂单:挖矿的下限,离最新价的百分比,如果是 1% 则填写 1|
|g_maxPercent|0.05|挂单:挖矿的上限,离最新价的百分比,如果是 1% 则填写 1|
|g_perAmount|35|挂单:每个订单量多少张,最多只能挂50个订单|
|g_kongtouAmount|35|挂单:|
|g_maxHoldingLong|700|挂单:多单最大持仓量|
|g_maxHoldingShort|700|挂单:空单最大持仓量|
|sp_jiancangAmount|true|市商/排序:减仓多仓|
|sp_jiacangAmount|true|市商/排序:增加多仓|
|sp_kongtouAmount|30|市商/排序: 空头数|
|sp_perAmount|30|市商/排序:单个订单大小|
|mainIntervel|false|Intervel|
|Intervel|false|Intervel0|
|sp_baseAmountLong|500|多仓|
|sp_baseAmountShort|500|空仓|
> 源码 (javascript)
``` javascript
exchange.IO("base", Url)//保证金市场风险巨大,你可能随时面临100%损失。或有不明bug100%损失,概不负责。
//实盘地址:https://api.fmex.com 测试网https://api.testnet.fmex.com//注意:先持仓long1u。
var ordersInfo = {//(加强版-增加仓位管理-增加时间设定-调整单量方向等-价格美丽/购买联系微信:ying5737)
buyId: 0,
buyPrice: 0,
sellId: 0,
sellPrice: 0,
minPrice: 0,
maxPrice: 0
}
var depthInfo = {//注意:先手动持仓long1u。
asks: [],
bids: []
}
function getTicker(symbol) {
url = "/v2/market/ticker/" + symbol;
data = exchange.IO("api", "GET", url);
return data.data;
}
function getAccounts() {
data = exchange.IO("api", "GET", "/v3/contracts/accounts")
return data.data;
}
function createOrderPrice(body) {
parameter = "symbol=" + body.symbol + "&type=" + body.type + "&direction=" + body.direction + "&post_only=" + body.post_only + "&price=" + body.price + "&quantity=" + body.quantity;
resultData = exchange.IO("api", "POST", "/v3/contracts/orders", parameter)
return resultData;
}
function createOrder(body) {
parameter = "symbol=" + body.symbol + "&type=" + body.type + "&direction=" + body.direction + "&quantity=" + body.quantity;
resultData = exchange.IO("api", "POST", "/v3/contracts/orders", parameter)
return resultData;
}
function getOrders() {
resultData = exchange.IO("api", "GET", "/v3/contracts/orders/open");
return resultData.data
}
function cancelOrder(id) {
resultData = exchange.IO("api", "POST", "/v3/contracts/orders/" + id + "/cancel");
return resultData;
}
function getPosition() {
resultData = exchange.IO("api", "GET", "/v3/broker/auth/contracts/positions");
return resultData.data;
}
function getMatches(id) {
resultData = exchange.IO("api", "GET", "/v3/contracts/orders/" + id + "/matches");
return resultData.data;
}
function getCandles(resolution, symbol) {
resultData = exchange.IO("api", "GET", "/v2/market/candles/" + resolution + "/" + symbol);
return resultData.data;
}
function cleanOrders(lastPrice) {
ordersInfo = getOrders();
orders = ordersInfo.results;
for (var i = 0; i < orders.length; i++) {
diffPercent = Math.abs(lastPrice - orders[i].price) / lastPrice * 100
if (diffPercent < g_minPercent || diffPercent > g_maxPercent) {
orderInfo = cancelOrder(orders[i].id);
Log("挂单取消订单:");
}
}
}
function getToOrderPrice(basePrice, direct) {
return parseInt(basePrice * (direct * (g_minPercent + Math.random() * (g_maxPercent - g_minPercent)) / 100 + 1))
}
function cleanPosition() {
res = getPosition();
res.results.forEach(function(it) {
if (it.symbol == 'BTCUSD_P') {
if (it.quantity) {
if (it.quantity > g_maxHoldingLong && it.direction.toUpperCase() == 'LONG') {
data = createOrder({
symbol: "BTCUSD_P",
type: "MARKET",
direction: it.direction.toUpperCase() == 'LONG' ? "SHORT" : "LONG",
quantity: 20,
})
Log("平仓:");
}
if (it.quantity > g_maxHoldingShort && it.direction.toUpperCase() == 'SHORT') {
data = createOrder({
symbol: "BTCUSD_P",
type: "MARKET",
direction: it.direction.toUpperCase() == 'LONG' ? "SHORT" : "LONG",
quantity: 20,
})
Log("平仓:");
}
}
}
});
}
function guadan() {
tickerInfo = getTicker('BTCUSD_P');
ticker = tickerInfo.ticker;
var lastPrice = ticker[0];
Log("lastPrice: "+lastPrice);
buyPrice = getToOrderPrice(lastPrice, -1);
sellPrice = getToOrderPrice(lastPrice, 1);
LongOrderInfo = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "LONG",
post_only: true,
price: buyPrice,
quantity: g_perAmount,
})
Log("挂单LONG:" );
shortOrderInfo = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: sellPrice,
quantity: g_kongtouAmount,
})
Log("挂单SHORT:" );
cleanOrders(lastPrice)
cleanPosition();
}
function shishang() {
Log("市商/排序挖矿**********************************");
tickerInfo = getTicker('BTCUSD_P');
ticker = tickerInfo.ticker;
Log("市商/排序挖矿ticker:");
lastPrice = ticker[0]
buyPrice = ticker[2]
sellPrice = ticker[4]
Log("lastPrice:"+lastPrice+":buyPrice:"+buyPrice+":sellPrice:" + sellPrice);
if (lastPrice == buyPrice) {
sellPrice = (buyPrice + 0.5).toFixed(1)
}
if (lastPrice == sellPrice) {
buyPrice = (sellPrice - 0.5).toFixed(1)
}
Log("buyPrice:"+buyPrice+":sellPrice:" + sellPrice);
// const LastK7 = k[7];
res = getPosition();
Log("市商/排序挖矿Position:" + JSON.stringify(res));
res.results.forEach(function(it) {
if (it.symbol == 'BTCUSD_P') {
if (it.quantity) {
if (it.quantity > sp_baseAmountLong && it.direction.toUpperCase() == 'LONG') {
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: lastPrice + 1.5,
quantity: sp_perAmount,
})
Log("排序10:" );
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: lastPrice + 2,
quantity: sp_perAmount,
})
Log("排序9:" );
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: lastPrice + 2.5,
quantity: sp_perAmount,
})
Log("排序8:");
} else if (it.quantity > sp_baseAmountShort && it.direction.toUpperCase() == 'SHORT') {
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "LONG",
post_only: true,
price: lastPrice - 0.5,
quantity: sp_perAmount,
})
Log("市商/排序-2:");
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "LONG",
post_only: true,
price: lastPrice - 1,
quantity: sp_perAmount,
})
Log("市商/排序-3:" );
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "LONG",
post_only: true,
price: lastPrice - 1.5,
quantity: sp_perAmount,
})
Log("市商/排序-4:" );
} else {
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: lastPrice - 3.5,
quantity: sp_perAmount,
})
Log("市商-3:" );
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: lastPrice - 4.5,
quantity: sp_perAmount,
})
Log("市商-4:" );
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "SHORT",
post_only: true,
price: lastPrice - 4,
quantity: sp_perAmount,
})
Log("市商-5:");
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "LONG",
post_only: true,
price: lastPrice - 2,
quantity: sp_perAmount,
})
Log("市商/排序-3:" );
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "LONG",
post_only: true,
price: lastPrice - 3.5,
quantity: sp_perAmount,
})
Log("市商/排序-4:" );
order = createOrderPrice({
symbol: "BTCUSD_P",
type: "LIMIT",
direction: "LONG",
post_only: true,
price: lastPrice - 4,
quantity: sp_perAmount,
})
Log("市商/排序-4:" );
}
}
}
})
}
/********************END 市商/排序挖矿***************************************************************************************************/
function main() {
while(true){
guadan();
Sleep(Intervel * 1000)
shishang()
Sleep(mainIntervel * 1000)
}
}//FMex排序挖矿多头版本代码使用说明。(注意api地址)(加强版-增加仓位管理-增加时间设定等-购买联系微信:ying5737)
```
> 策略出处
https://www.fmz.com/strategy/178700
> 更新时间
2019-12-21 07:31:42
-169
View File
@@ -1,169 +0,0 @@
> 策略名称
MACD交易策略btc合约版
> 策略作者
groot
> 策略描述
一个简单的macd策略
周期四小时
金叉做多
死叉做空
杠杆均为一倍
因为是反向系统,不带止损
回测了下两年数据,币本位年化130%,最大回撤30%
另外回测了另一种macd策略
水上做多
水下做空
杠杆均一倍,也不带止损
回测了两年数据,币本位才30%,回撤15%左右。
所以可以得出,金叉死叉的指标有效性要高很多;
其实从逻辑上来讲也容易理解,金叉反应的是快线拐头向上,代表的是一种趋势方向,水上反应的只是当前时间点的差值,并不能很好反应方向;
如果用快线的窗口差值当做一个指标,比如当前快线和上个快线的差值大于某个阀值就做多,那也能达到跟金叉同样的效果;只是如果阀值设置不合理,有可能在震荡行情中,会频繁产生无效交易信号。
另外,周期分别回测了小时线、四小时线、日线,指标有效性排序:日线>四小时线>小时线;其实也很好理解,金叉死叉属于趋势策略,周期越长有效性越高。
关于macd的第三个参数,移动平均周期,默认设置的9,改成10效果会更好,该值越大,快线慢线的间隔越大,也就越能避免震荡行情频繁产生无效交易信号,不过太大的话,进入趋势行情的时间就晚了。
> 策略参数
|参数|默认值|描述|
|----|----|----|
|short|12|short|
|long|26|long|
|m|10|m|
|threshold|5|threshold|
|fresh_rete|4|交易频率(小时)|
> 源码 (python)
``` python
# 回测配置
'''backtest
start: 2018-01-01 00:00:00
end: 2020-03-01 00:00:00
period: 1d
exchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD","stocks":1}]
'''
mp = 0 # 定义一个全局变量,用于控制虚拟持仓
counts = 0 # 定义一个全局变量,用于控制开单张数
# 判断两根两个数组是否金叉
def is_up_cross(arr1, arr2):
if arr1[-2] < arr2[-2] and arr1[-1] > arr2[-1]:
return True
# 判断两根两个数组是否死叉
def is_down_cross(arr1, arr2):
if arr1[-2] > arr2[-2] and arr1[-1] < arr2[-1]:
return True
# 判断水上
def is_up(arr1):
if arr1[-1] > threshold:
return True
# 判断水下
def is_down(arr1):
if arr1[-1] < -threshold:
return True
# 程序主函数
def onTick():
exchange.SetContractType("quarter")
#金本位合约
#exchange.IO("currency", "BTC_USDT")
bar_arr = exchange.GetRecords(fresh_rete*60*60) # 获取4小时的K线数组
#if _D(bar_arr[-1]['Time']/1000) < '2020-01-05 00:00:00':
# Log("bar_arr",len(bar_arr))
if len(bar_arr) < long + m + 1: # 如果K线数组长度太小,就不能计算MACD,所以直接返回跳过
return
all_macd = TA.MACD(bar_arr, short, long, m) # 计算MACD值,返回的是一个二维数组
dif = all_macd[0] # 获取DIF的值,返回一个数组
dif.pop() # 删除DIF数组最后一个元素,因为最后一跟k线还未形成
dea = all_macd[1] # 获取DEA的值,返回一个数组
dea.pop() # 删除DEA数组最后一个元素,因为最后一跟k线还未形成
last_close = bar_arr[-1]['Close'] # 获取最新价格(卖价),用于开平仓
global mp # 全局变量,用于控制虚拟持仓
global counts # 全局变量,用于记录上次开单张数
#杠杆倍数
acct = exchange.GetAccount()
portfolio_value = (acct.Stocks+acct.FrozenStocks)*last_close
counts_tmp = int(portfolio_value/100)
#开仓
if mp == 0 :
#多单
if is_up_cross(dif, dea):
#if is_up(dif):
exchange.SetDirection("buy") # 设置交易方向和类型
exchange.Buy(last_close + 10, counts_tmp) # 开多单
counts = counts_tmp
Log("bar_arr",bar_arr[-1],"dif",dif[-1],"dea",dea[-1])
mp = 1 # 设置虚拟持仓的值,即有多单
#空单
if is_down_cross(dif, dea):
#if is_down(dif):
exchange.SetDirection("sell") # 设置交易方向和类型
exchange.Sell(last_close - 10, counts_tmp) # 开空单
counts = counts_tmp
Log("bar_arr",bar_arr[-1],"dif",dif[-1],"dea",dea[-1])
mp = -1 # 设置虚拟持仓的值,即有空单
#平多开空
if mp == 1 and is_down_cross(dif, dea):
#if mp == 1 and is_down(dif,):
exchange.SetDirection("closebuy") # 设置交易方向和类型
exchange.Sell(last_close - 10, counts) # 平多单
exchange.SetDirection("sell") # 设置交易方向和类型
exchange.Sell(last_close - 10, counts_tmp) # 开空单
counts = counts_tmp
Log("bar_arr",bar_arr[-1],"dif",dif[-1],"dea",dea[-1])
mp = -1
# 平空开多
if mp == -1 and is_up_cross(dif, dea):
#if mp == -1 and is_up(dif):
exchange.SetDirection("closesell") # 设置交易方向和类型
exchange.Buy(last_close + 10, counts) # 平空单
exchange.SetDirection("buy") # 设置交易方向和类型
exchange.Buy(last_close + 10, counts_tmp) # 开多单
counts = counts_tmp
Log("bar_arr",bar_arr[-1],"dif",dif[-1],"dea",dea[-1])
mp = 1
def main():
while True:
onTick()
Sleep(fresh_rete*60*60*1000)
```
> 策略出处
https://www.fmz.com/strategy/188100
> 更新时间
2020-03-06 12:01:46
+219
View File
@@ -0,0 +1,219 @@
> 策略名称
MACD低买高卖自动跟单滑动止损
> 策略作者
John
> 策略参数
|参数|默认值|描述|
|----|----|----|
|ac1|0.005|交叉后第一柱|
|bc1|-1e-06|交叉后前一柱|
|SlidePrice|0.3|滑动价格|
|TrailingStop|0.5|止损点|
|orderTimeout|30|买单超时(秒)|
|MinStock|30|最小持仓|
> 源码 (javascript)
``` javascript
Fixed = function(v) {
return Math.floor(v*1000)/1000;
};
// for orders
WaitOrder = function(exchange, orderId, timeoutToCancel) {
var ts = (new Date()).getTime();
while (true) {
Sleep(3000);
var orderInfo = exchange.GetOrder(orderId);
if (!orderInfo) {
continue;
}
if (orderInfo.Status == ORDER_STATE_CLOSED || orderInfo.Status == ORDER_STATE_CANCELED) {
return orderInfo;
}
if (((new Date()).getTime() - ts) > timeoutToCancel) {
exchange.CancelOrder(orderId);
}
}
};
Buy = function(exchange, maxPrice, slidePrice, balanceRatio, timeoutS) {
var ts = (new Date()).getTime();
var account;
var dealAmount = 0.0;
var usedBlance = 0.0;
var maxBalanceUse = 0.0;
var isFirst = true;
do {
if (isFirst) {
isFirst = false;
} else {
Sleep(3000);
}
var ticker = exchange.GetTicker();
if (!ticker) {
continue;
}
var buyPrice = ticker.Sell + slidePrice;
// Price too high, wait...
if (buyPrice > maxPrice) {
continue;
}
// Initialize at first
if (!account) {
account = exchange.GetAccount();
if (!account) {
continue;
}
// Initialize maxBalanceUse
maxBalanceUse = account.Balance * balanceRatio;
}
var buyAmount = Fixed((maxBalanceUse - usedBlance) / buyPrice);
if (buyAmount < MinStock) {
break;
}
orderId = exchange.Buy(buyPrice, buyAmount);
if (!orderId) {
Log(buyPrice, buyAmount, maxBalanceUse, usedBlance);
continue;
}
var orderInfo = WaitOrder(exchange, orderId, timeoutS);
dealAmount += orderInfo.DealAmount;
usedBlance += orderInfo.Price * orderInfo.DealAmount;
if (orderInfo.Status == ORDER_STATE_CLOSED) {
break;
}
} while (((new Date()).getTime() - ts) < timeoutS);
return {amount: dealAmount, price: (dealAmount > 0 ? usedBlance / dealAmount : 0)};
};
Sell = function(exchange, sellAmount, slidePrice) {
// Account info must set
var account = exchange.GetAccount();
while (!account) {
Sleep(2000);
account = exchange.GetAccount();
}
sellAmount = Math.min(sellAmount, account.Stocks);
var cash = 0.0;
var remain = sellAmount;
while (remain >= exchange.GetMinStock()) {
var ticker = exchange.GetTicker();
if (!ticker) {
Sleep(2000);
continue;
}
var sellPrice = ticker.Buy - slidePrice;
var sellOrderId = exchange.Sell(sellPrice, remain);
if (!sellOrderId) {
Sleep(2000);
continue;
}
var orderInfo = WaitOrder(exchange, sellOrderId, 10000);
remain -= orderInfo.DealAmount;
cash += orderInfo.Price * orderInfo.DealAmount;
}
return {amount: sellAmount, price: (sellAmount > 0 ? cash / sellAmount : 0)};
};
var BuyInfo;
var BanlanceRatio = 1.0;
var Profit = 0.0;
var timeAtBuy = 0;
function onTick(exchange) {
var ticker = exchange.GetTicker();
var records = exchange.GetRecords();
if (!ticker || !records || records.length < 45) {
return;
}
var ticks = [];
for (var i = 0; i < records.length; i++) {
ticks.push(records[i].Close);
}
var macd = TA.MACD(records, 12, 26, 9);
var dif = macd[0];
var dea = macd[1];
var his = macd[2];
var op = 0;
if (!BuyInfo) {
if (dif[ticks.length-1] > 0 && his[ticks.length-1] > ac1 && his[ticks.length-2] < bc1) {
op = 1;
}
} else {
if (records[records.length-2].Time > timeAtBuy && records[records.length-1].Close < records[records.length-1].Open - 0.5
&& records[records.length-2].Close < records[records.length-2].Open - 0.5
&& records[records.length-1].Close < records[records.length-2].Close - 0.5) {
op = 2;
} else if (records[records.length-2].Time > timeAtBuy && BuyInfo.price > records[records.length-1].Close && records[records.length-1].Close < records[records.length-1].Open - 0.5) {
op = 2;
} else if ((BuyInfo.price < ticker.Last || dif[ticks.length-1] < 0) && his[ticks.length-1] <= 0) {
op = 2;
} else if ((BuyInfo.price > ticker.Last) && ((BuyInfo.price - ticker.Last) / BuyInfo.price > TrailingStop)) {
op = 2;
}
}
if (op == 1) {
var info = Buy(exchange, ticker.Sell + (SlidePrice * 3), SlidePrice, BanlanceRatio, orderTimeout * 1000);
if (info.amount > 0) {
BuyInfo = info;
timeAtBuy = records[records.length-1].Time;
}
} else if (op == 2) {
var info = Sell(exchange, BuyInfo.amount, SlidePrice);
if (info.amount > 0) {
Profit += info.amount * (info.price - BuyInfo.price);
LogProfit(Profit);
BuyInfo = null;
}
}
}
function main() {
var account = exchange.GetAccount();
if (account) {
Log(exchange.GetName(), exchange.GetCurrency(), account);
}
while (true) {
onTick(exchange);
Sleep(30000);
}
}
```
> 策略出处
https://www.fmz.com/strategy/194224
> 更新时间
2020-04-14 12:00:26
+18 -5
View File
@@ -4,11 +4,28 @@
> 开源策略
- [商品期货多品种主力自动移仓海龟交易策略](https://www.fmz.com/strategy/17289)
- [币安永续多币种对冲策略原版(做多超跌做空超涨)4月13日最新止损模块](https://www.fmz.com/strategy/195226)
- [okex合约交易测试](https://www.fmz.com/strategy/199102)
- [RecordsCollecter (教学)](https://www.fmz.com/strategy/199120)
- [多平台对冲稳定套利](https://www.fmz.com/strategy/194150)
- [期货做市高频交易策略](https://www.fmz.com/strategy/194180)
- [币安永续多币种对冲策略(做空或做多山寨币指数)4月10日改进Bug,需要更新](https://www.fmz.com/strategy/194825)
- [用FMZ的均线的交易方式PYTHON版本2](https://www.fmz.com/strategy/198397)
- [MACD低买高卖自动跟单滑动止损](https://www.fmz.com/strategy/194224)
- [一根均线 趋势 Demo](https://www.fmz.com/strategy/193609)
- [混合图表的一个复杂例子](https://www.fmz.com/strategy/196963)
- [麦语言海龟策略体验](https://www.fmz.com/strategy/126968)
- [币安策略二去掉高低分](https://www.fmz.com/strategy/196445)
- [测试多图表展示](https://www.fmz.com/strategy/38203)
- [简单的股票趋势跟踪交易策略](https://www.fmz.com/strategy/195935)
- [合约下单](https://www.fmz.com/strategy/195453)
- [网格变形策略之单边网格 (OK期货)](https://www.fmz.com/strategy/8474)
- [测试现货买卖操作(分限价、市价两种情况)](https://www.fmz.com/strategy/191349)
- [固定间距批量挂单插件](https://www.fmz.com/strategy/190017)
- [期货一键平仓插件|Cover all contracts](https://www.fmz.com/strategy/191363)
- [交易所上新币第一时间挂单机器人](https://www.fmz.com/strategy/194206)
- [C++期货高频套币策略OKEX Websocket版](https://www.fmz.com/strategy/163447)
- [一根均线 趋势 Demo](https://www.fmz.com/strategy/193609)
- [8.13 R-Breaker交易策略](https://www.fmz.com/strategy/187009)
- [CTP商品期货多品种均线策略](https://www.fmz.com/strategy/193043)
- [割庄神器](https://www.fmz.com/strategy/191622)
@@ -183,12 +200,10 @@
- [海龟](https://www.fmz.com/strategy/128382)
- [OKEX期现对冲](https://www.fmz.com/strategy/127939)
- [现现对冲(搬砖)](https://www.fmz.com/strategy/127154)
- [测试多图表展示](https://www.fmz.com/strategy/38203)
- [选择性套利](https://www.fmz.com/strategy/134371)
- [MACD+MA指标组合策略](https://www.fmz.com/strategy/128134)
- [(学习)API与教程内代码学习文件](https://www.fmz.com/strategy/131864)
- [封装Bithumb的ordersDetail接口](https://www.fmz.com/strategy/132241)
- [麦语言海龟策略体验](https://www.fmz.com/strategy/126968)
- [Bitmex仓位变化推送微信(wss协议,需要bitmex api ID)|Bitmex position-change push(websocket)](https://www.fmz.com/strategy/128624)
- [基于ATR波动率指标构建的通道策略|Channel strategy based on ATR volatility indicator](https://www.fmz.com/strategy/127691)
- [升级版恒温器策略|Upgraded Thermostat Strategy](https://www.fmz.com/strategy/129086)
@@ -254,7 +269,6 @@
- [计划委托卖出](https://www.fmz.com/strategy/747)
- [单点狙击高频加仓自动反手解套算法 V1.2](https://www.fmz.com/strategy/2406)
- [抢盘口做市策略 - 高频逼近型](https://www.fmz.com/strategy/348)
- [网格变形策略之单边网格 (OK期货)](https://www.fmz.com/strategy/8474)
- [测试-CTP商品期货连接状态 (图表显示)](https://www.fmz.com/strategy/22838)
- [图表模板(增加状态栏表格)](https://www.fmz.com/strategy/20967)
- [测试-布林带策略(基于策略框架)](https://www.fmz.com/strategy/28128)
@@ -274,7 +288,6 @@
- [多平台强制滑动平仓(买一价)](https://www.fmz.com/strategy/99)
- [定点进场下单定点离场卖单](https://www.fmz.com/strategy/64)
- [【001】单平台均衡策略 【研究】](https://www.fmz.com/strategy/82325)
- [CTP商品期货多品种海龟交易策略](https://www.fmz.com/strategy/17289)
- [python版 Dual Thrust OKCoin 期货](https://www.fmz.com/strategy/21856)
- [五线向上&&突破前高](https://www.fmz.com/strategy/76827)
- [C++ API调用例子](https://www.fmz.com/strategy/61533)
+94
View File
@@ -0,0 +1,94 @@
> 策略名称
RecordsCollecter (教学)
> 策略作者
小小梦
> 策略描述
相关文章:https://www.fmz.com/bbs-topic/5425
> 策略参数
|参数|默认值|描述|
|----|----|----|
|dropNames|[]|删除表的名称|
> 源码 (python)
``` python
import pymongo
import json
def main():
Log("测试数据收集")
# 连接数据库服务
myDBClient = pymongo.MongoClient("mongodb://localhost:27017") # mongodb://127.0.0.1:27017
# 创建数据库
huobi_DB = myDBClient["huobi"]
# 打印目前数据库表
collist = huobi_DB.list_collection_names()
Log("collist:", collist)
# 检测是否删除表
arrDropNames = json.loads(dropNames)
if isinstance(arrDropNames, list):
for i in range(len(arrDropNames)):
dropName = arrDropNames[i]
if isinstance(dropName, str):
if not dropName in collist:
continue
tab = huobi_DB[dropName]
Log("dropName:", dropName, "删除:", dropName)
ret = tab.drop()
collist = huobi_DB.list_collection_names()
if dropName in collist:
Log(dropName, "删除失败")
else :
Log(dropName, "删除成功")
# 创建records表
huobi_DB_Records = huobi_DB["records"]
# 请求数据
preBarTime = 0
index = 1
while True:
r = _C(exchange.GetRecords)
if len(r) < 2:
Sleep(1000)
continue
if preBarTime == 0:
# 首次写入所有BAR数据
for i in range(len(r) - 1):
# 逐根写入
bar = r[i]
huobi_DB_Records.insert_one({"index": index, "High": bar["High"], "Low": bar["Low"], "Open": bar["Open"], "Close": bar["Close"], "Time": bar["Time"], "Volume": bar["Volume"]})
index += 1
preBarTime = r[-1]["Time"]
elif preBarTime != r[-1]["Time"]:
bar = r[-2]
huobi_DB_Records.insert_one({"index": index, "High": bar["High"], "Low": bar["Low"], "Open": bar["Open"], "Close": bar["Close"], "Time": bar["Time"], "Volume": bar["Volume"]})
index += 1
preBarTime = r[-1]["Time"]
LogStatus(_D(), "preBarTime:", preBarTime, "_D(preBarTime):", _D(preBarTime/1000), "index:", index)
Sleep(10000)
```
> 策略出处
https://www.fmz.com/strategy/199120
> 更新时间
2020-04-16 15:18:28
-253
View File
@@ -1,253 +0,0 @@
> 策略名称
fcoin-多空力量排序
> 策略作者
小天才收割机
> 策略描述
fcoin挖矿策略
盘口多空比排序挖矿
> 策略参数
|参数|默认值|描述|
|----|----|----|
|Interval|1000|出错重试间隔(毫秒)|
|LoopInterval|0.1|轮询间隔(秒)|
|Step|0.1|网格间隔(元)|
|Lot|0.005|手数|
|MaxNets|6|最大网格数|
|DisableLog|false|关闭订单跟踪|
|MinStock|0.01|最小交易币数|
|amountPrecision|4|数量精度|
|pricePrecision|true|价格精度|
|level|true|计算均价深度|
|BUY_START_LEVEL|5|买单起始深度|
|SELL_START_LEVEL|5|卖单起始深度|
|ratioThresh|2|挂单量比值阈值|
|DepthLevel|6|统计深度|
> 源码 (javascript)
``` javascript
function CancelPendingOrders() {
var orders = _C(exchange.GetOrders);
for (var j = 0; j < orders.length; j++) {
exchange.CancelOrder(orders[j].Id, orders[j]);
}
}
function onexit() {
CancelPendingOrders();
Sleep(100);
Log("exit");
}
var initPrice = _C(exchange.GetTicker).Buy;
var currency = _C(exchange.GetCurrency);
if(currency == "BTC_USDT") {
MinStock = 0.005;
amountPrecision = 4;
pricePrecision = 1;
} else if(currency == "ETH_USDT") {
MinStock = 0.05;
amountPrecision = 4;
pricePrecision = 2;
} else if(currency == "LTC_USDT") {
MinStock = 0.5;
amountPrecision = 4;
pricePrecision = 2;
} else if(currency == "EOS_USDT") {
MinStock = 1;
amountPrecision = 4;
pricePrecision = 3;
} else if(currency == "XRP_USDT") {
MinStock = 10;
amountPrecision = 2;
pricePrecision = 4;
} else if(currency == "BCH_USDT") {
MinStock = 0.05;
amountPrecision = 4;
pricePrecision = 1;
}
Step = 1 / Math.pow(10, pricePrecision);
MaxNets = 50;
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) * initPrice);
LogProfit(_N(netNow - netInit, 2));
}
var LastOrdersLength = null;
var initAccount = _C(exchange.GetAccount);
var initPrice = _C(exchange.GetTicker).Last;
var initInUSD = _N(initAccount.Stocks * initPrice + initAccount.Balance, 2);
function calcDepth(orders) {
var base = parseInt(orders[0].Price);
var allAmount = 0;
var n = 0;
for (var i = 0; i < orders.length && n < DepthLevel; i++) {
var p = parseInt(orders[i].Price);
if (p != base) {
n++;
base = p;
}
allAmount += orders[i].Amount;
}
return allAmount;
}
function onTick() {
var ticker = _C(exchange.GetTicker);
var account = _C(exchange.GetAccount);
var orders = _C(exchange.GetOrders);
var depth = _C(exchange.GetDepth);
if (LastOrdersLength != null && LastOrdersLength != orders.length) {
updateProfit(initAccount, account, ticker);
}
LastOrdersLength = orders.length;
var currentInUSD = _N(account.Stocks * ticker.Last + account.Balance, 2);
LogProfit(currentInUSD - initInUSD, "&");
var msg = "";
msg += "lastPrice = " + ticker.Last + "\n" +
"初始币:" + initAccount.Stocks + ",初始钱:" + initAccount.Balance + ", initUSD:" + initInUSD + "\n" +
"当前币:" + account.Stocks + ",当前钱:" + account.Balance + ", currentUSD:" + currentInUSD;
// 多空力量对比
var asksAmount = calcDepth(depth.Asks);
var bidsAmount = calcDepth(depth.Bids);
var ratio = Math.max(asksAmount/bidsAmount, bidsAmount/asksAmount);
ratio = asksAmount > bidsAmount ? ratio : -ratio;
var buy_start_level = BUY_START_LEVEL;
var sell_start_level = SELL_START_LEVEL;
if(ratio > ratioThresh) {
buy_start_level = 1;
sell_start_level = 6;
} else if(ratio <= -2) {
sell_start_level = 1;
buy_start_level = 6;
}
//var buy = depth.Bids[level].Price;
//var sell = depth.Asks[level].Price;
// 盘口上下加权平均
var avg_buy = 0;
var buy_amount = 0;
var avg_sell = 0;
var sell_amount = 0;
for(var i = 1; i <= level; ++i) {
avg_buy += depth.Bids[i - 1].Price * depth.Bids[i - 1].Amount;
buy_amount += depth.Bids[i - 1].Amount;
avg_sell += depth.Asks[i - 1].Price * depth.Asks[i - 1].Amount;
sell_amount += depth.Asks[i - 1].Amount;
}
var buy = _N(avg_buy / buy_amount, pricePrecision);
var sell = _N(avg_sell / sell_amount, pricePrecision);
//var mid = adjustFloat(ticker.Buy + ((ticker.Sell - ticker.Buy) / 2));
var mid = _N(buy + ((sell - buy) / 2), pricePrecision);
// var numBuy = parseInt(Math.min(MaxNets / 2 , (mid - buy) / Step, account.Balance / buy / Lot));
var numBuy = parseInt(Math.min(MaxNets / 2, account.Balance / buy / Lot));
var numSell = parseInt(Math.min(MaxNets / 2, account.Stocks / Lot));
var num = Math.max(numBuy, numSell);
msg += "\nticker.sell = " + ticker.Sell + ", ticker.buy = " + ticker.Buy +
", mid = " + _N((ticker.Buy + ticker.Sell) / 2, pricePrecision) + "\n" +
"avg_sell = " + sell + ", avg_buy = " + buy + ", mid = " + mid;
msg += "\n多/空 = " + ratio;
LogStatus(msg);
var ordersKeep = [];
var queue = [];
for(var i = buy_start_level; i < numBuy + buy_start_level; ++i) {
var buyPrice = _N(mid - (i * Step), pricePrecision);
var alreadyBuy = false;
for (j = 0; j < orders.length; j++) {
if (orders[j].Type == ORDER_TYPE_BUY) {
if (Math.abs(orders[j].Price - buyPrice) < (Step / 2)) {
alreadyBuy = true;
ordersKeep.push(orders[j].Id);
}
}
}
if ((!alreadyBuy) && (i < numBuy)) {
queue.push([buyPrice, ORDER_TYPE_BUY]);
}
}
for(var i = sell_start_level; i < numSell + sell_start_level; ++i) {
var sellPrice = _N(mid + (i * Step), pricePrecision);
var alreadySell = false;
for (j = 0; j < orders.length; j++) {
if (orders[j].Type == ORDER_TYPE_SELL) {
if (Math.abs(orders[j].Price - sellPrice) < (Step / 2)) {
alreadySell = true;
ordersKeep.push(orders[j].Id);
}
}
}
if ((!alreadySell) && (i < numSell)) {
queue.push([sellPrice, ORDER_TYPE_SELL]);
}
}
for (var i = 0; i < orders.length; i++) {
var keep = false;
for (var j = 0; j < ordersKeep.length; j++) {
if (orders[i].Id == ordersKeep[j]) {
keep = true;
}
}
if (!keep) {
exchange.CancelOrder(orders[i].Id);
LastOrdersLength--;
}
}
for (var i = 0; i < queue.length; i++) {
if (queue[i][1] == ORDER_TYPE_BUY) {
exchange.Buy(_N(queue[i][0], pricePrecision), Lot);
} else {
exchange.Sell(_N(queue[i][0], pricePrecision), Lot);
}
LastOrdersLength++;
}
}
function main() {
if (DisableLog) {
EnableLog(false);
}
Log(initAccount);
LoopInterval = Math.max(LoopInterval, 1);
// Lot = Math.max(MinStock, Lot);
Lot = MinStock;
while (true) {
onTick();
Sleep(LoopInterval * 1000);
}
}
```
> 策略出处
https://www.fmz.com/strategy/161034
> 更新时间
2019-12-26 11:24:50
-66
View File
@@ -1,66 +0,0 @@
> 策略名称
fcoin挖矿演示
> 策略作者
张超
> 策略描述
看到官方api群里开源的python版本,虽然很简单了,但是还有很多人架不起来环境
出问题的原因也有很多种,不太适合新手
本着开源共享的精神,我也开源一份,请大家斧正
> 策略参数
|参数|默认值|描述|
|----|----|----|
|Amount|10|下单量|
|Wait|true|等待间隔(秒)|
> 源码 (javascript)
``` javascript
function DealOrder(orderType, sellPrice) {
var ticker = _C(exchange.GetTicker);
var action = orderType == ORDER_TYPE_BUY ? 'Buy' : 'Sell';
_C(exchange[action], (orderType == ORDER_TYPE_SELL ? sellPrice : ticker.Last), Amount);
var recentPrice = ticker.Last;
while (true) {
Sleep(Wait*1000);
var orders = _C(exchange.GetOrders);
if (orders == 0) {
break;
}
ticker = _C(exchange.GetTicker);
_.each(orders, function(o) {
if (o.DealAmount == 0 && ((o.Type == ORDER_TYPE_SELL && ticker.Last >= sellPrice && ticker.Last != recentPrice) || (ticker.Last != recentPrice && o.Type == ORDER_TYPE_BUY))) {
exchange.CancelOrder(o.Id);
recentPrice = ticker.Last
_C(exchange[action], ticker.Last, Amount);
}
});
}
return recentPrice;
}
function main() {
while (true) {
DealOrder(ORDER_TYPE_SELL, DealOrder(ORDER_TYPE_BUY));
Sleep(1000);
}
}
```
> 策略出处
https://www.fmz.com/strategy/97791
> 更新时间
2018-06-12 10:28:01
+57
View File
@@ -0,0 +1,57 @@
> 策略名称
okex合约交易测试
> 策略作者
a838899
> 源码 (python)
``` python
'''backtest
start: 2019-07-22 00:00:00
end: 2020-03-29 00:00:00
period: 1d
exchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD"}]
args: [["StopLossRatio",0.1],["Interval",5]]
'''
def main():
#Log(exchange.GetAccount())
exchange.SetContractType("this_week")
exchange.SetMarginLevel(10)
# 开多单,买币
exchange.SetDirection("buy")
exchange.Buy(20000,1)
position = _C(exchange.GetPosition)
Log(position)
# 平多单,卖币
exchange.SetDirection("closebuy")
exchange.Sell(10000,1)
Log(position)
# 开空单,卖币
exchange.SetDirection("sell")
exchange.Sell(10000,1)
Log(position)
# 平空单,买币
exchange.SetDirection("closesell")
exchange.Buy(20000,1)
Log(position)
Log("Amount:", position[0].Amount, "FrozenAmount:", position[0].FrozenAmount,"Price:",
position[0].Price, "Profit:", position[0].Profit,"Type:", position[0].Type, "ContractType:", position[0].ContractType)
```
> 策略出处
https://www.fmz.com/strategy/199102
> 更新时间
2020-04-16 16:37:56
+1 -1
View File
@@ -103,4 +103,4 @@ https://www.fmz.com/strategy/193609
> 更新时间
2020-03-28 20:56:30
2020-04-11 21:28:30
+148
View File
@@ -0,0 +1,148 @@
> 策略名称
合约下单
> 策略作者
一拳男孩
> 策略描述
### $.openPos(buy|sell, amount);
开仓
### $.closePos(buy|sell, amount);
平仓
> 策略参数
|参数|默认值|描述|
|----|----|----|
|SLIP_POINT|0.01|滑点|
|TRADE_TIMEOUT|10|交易超时|
|FACE_VALUE|10|面值|
|PRICE_PRECISION|4|价格精度|
|AMOUNT_PRECISION|8|交易量精度|
> 源码 (javascript)
``` javascript
/*backtest
start: 2020-01-08 00:00:00
end: 2020-04-06 00:00:00
period: 1d
exchanges: [{"eid":"Futures_OKCoin","currency":"ETH_USD","stocks":1400}]
args: [["PRICE_PRECISION",2],["AMOUNT_PRECISION",4]]
*/
var tempOrders = [];
var COLOR = {
GREEN: '#00a500',
RED: '#ff0000',
GRAY: '#b2b2b2',
ORANGE: '#ff9e38'
}
function cancelOrder(ex,order_id){
if (!order_id) return Log('不正确的订单id', order_id);
Log("取消订单" + order_id);
ex.CancelOrder(order_id);
Sleep(500);
var orders=_C(ex.GetOrders);
var find=false;
for (var i=0;i<orders.length;++i){
if (orders[i].Id===order_id){
find=true;
break;
}
}
if (find){
cancelOrder(ex.order_id);
}
}
var trade = function(direction, amount) {
var ticker = _C(exchange.GetTicker);
exchange.SetDirection(direction);
var price = 0
if (_.contains(['buy', 'closesell'], direction)) {
price = _N(new Decimal(ticker.Last).plus(SLIP_POINT).toNumber(), PRICE_PRECISION);
} else {
price = _N(new Decimal(ticker.Last).minus(SLIP_POINT).toNumber(), PRICE_PRECISION);
}
var orderInfo = null;
var avgPrice = null;
var oid = null;
var beginTime = null;
var dealAmount = _.reduce(tempOrders, function(p, n) {
return new Decimal(p).plus(n.DealAmount).toNumber();
}, 0);
var remainAmount = Math.floor(new Decimal(amount).minus(dealAmount).toNumber());
if (remainAmount < 1) {
avgPrice = _N(new Decimal(_.reduce(tempOrders, function(p, n) {
return new Decimal(p).plus(new Decimal(n.AvgPrice).mul(n.DealAmount).mul(FACE_VALUE)).toNumber()
}, 0)).div(new Decimal(dealAmount).mul(FACE_VALUE)).toNumber(), PRICE_PRECISION);
orderInfo = {
Id: _.last(tempOrders).Id,
Type: _.contains(['buy', 'closebuy'], direction) ? PD_LONG : PD_SHORT,
Price: price,
AvgPrice: avgPrice,
Amount: amount,
DealAmount: dealAmount,
Orders: _.pluck(tempOrders, 'Id')
}
tempOrders = [];
return orderInfo;
} else {
oid = _.contains(['buy', 'closesell'], direction) ? exchange.Buy(price, remainAmount) : exchange.Sell(price, remainAmount);
if (oid) {
beginTime = Unix();
while(1) {
orderInfo = _C(exchange.GetOrder, oid);
if (orderInfo.Status !== ORDER_STATE_PENDING) {
tempOrders.push(orderInfo);
return trade(direction, amount);
}
if (Unix() - beginTime >= TRADE_TIMEOUT) {
Log('交易超时, 撤销订单' + oid + COLOR.RED);
cancelOrder(exchange, oid);
continue;
}
Sleep(250);
}
} else {
return null;
}
}
}
$.OpenPos = function(direction, amount) {
return trade(direction, amount);
};
$.ClosePos = function(direction, amount) {
return trade('close' + direction, amount);
}
function main() {
exchange.SetContractType('this_week');
exchange.SetPrecision(PRICE_PRECISION, 0);
Log($.OpenPos('buy', 2));
$.OpenPos('sell', 1);
$.ClosePos('buy', 1);
$.ClosePos('buy', 1);
$.ClosePos('sell', 1);
Log(exchange.GetPosition());
}
```
> 策略出处
https://www.fmz.com/strategy/195453
> 更新时间
2020-04-07 01:25:52
@@ -0,0 +1,486 @@
> 策略名称
商品期货多品种主力自动移仓海龟交易策略
> 策略作者
Zero
> 策略描述
> 功能
- 主力连续或者指数合约自动移仓换月
- 支持自动或手动恢复进度
- 可同时操作多个不同品种
- 增加时间段区分与各种网络错误问题的应对处理
> 运行状态
![IMG](https://www.fmz.com/upload/asset/b879a71edbbb13d63d.png)
> 回测示例
![IMG](https://www.fmz.com/upload/asset/1459b171f03bb578ba8.png)
> 策略参数
|参数|默认值|描述|
|----|----|----|
|Instruments|MA888,pp888,v888,rb888,jm888|合约列表|
|CustomBalance|false|定义启动资金|
|InitBalance|false|启动资金|
|LoopInterval|3|轮询周期(秒)|
|RiskRatio|true|% Risk Per N ( 0 - 100)|
|ATRLength|20|ATR计算周期|
|EnterPeriodA|20|系统一入市周期|
|LeavePeriodA|10|系统一离市周期|
|EnterPeriodB|55|系统二入市周期|
|LeavePeriodB|20|系统二离市周期|
|UseEnterFilter|true|使用入市过滤|
|IncSpace|0.5|加仓间隔(N的倍数)|
|StopLossRatio|2|止损系数(N的倍数)|
|MaxLots|4|单品种加仓次数|
|RMode|0|进度恢复模式: 自动|手动|
|VMStatus|{}|手动恢复字符串|
|WXPush|true|推送交易信息|
|MaxTaskRetry|5|开仓最多重试次数|
|KeepRatio|20|预留保证金比例|
|按钮|默认值|描述|
|----|----|----|
|暂停/继续|__button__|暂停/继续|
> 源码 (javascript)
``` javascript
/*backtest
start: 2016-05-01 00:00:00
end: 2020-02-15 23:59:00
period: 1d
exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}]
*/
var _q = $.NewTaskQueue();
var TTManager = {
New: function(needRestore, symbol, initBalance, keepBalance, riskRatio, atrLen, enterPeriodA, leavePeriodA, enterPeriodB, leavePeriodB, useFilter,
multiplierN, multiplierS, maxLots) {
// subscribe
var symbolDetail = _C(exchange.SetContractType, symbol);
if (symbolDetail.VolumeMultiple == 0 || symbolDetail.MaxLimitOrderVolume == 0 || symbolDetail.MinLimitOrderVolume == 0 || symbolDetail.LongMarginRatio == 0 || symbolDetail.ShortMarginRatio == 0) {
Log(symbolDetail);
throw "合约信息异常";
} else {
Log("合约", symbolDetail.InstrumentName, "一手", symbolDetail.VolumeMultiple, "份, 最大下单量", symbolDetail.MaxLimitOrderVolume, "保证金率:", _N(symbolDetail.LongMarginRatio), _N(symbolDetail.ShortMarginRatio), "交割日期", symbolDetail.StartDelivDate);
}
var obj = {
symbol: symbol,
tradeSymbol: symbolDetail.InstrumentID,
initBalance: initBalance,
keepBalance: keepBalance,
riskRatio: riskRatio,
atrLen: atrLen,
enterPeriodA: enterPeriodA,
leavePeriodA: leavePeriodA,
enterPeriodB: enterPeriodB,
leavePeriodB: leavePeriodB,
useFilter: useFilter,
multiplierN: multiplierN,
multiplierS: multiplierS
};
obj.maxLots = maxLots;
obj.lastPrice = 0;
obj.symbolDetail = symbolDetail;
obj.status = {
symbol: symbol,
recordsLen: 0,
vm: [],
open: 0,
cover: 0,
st: 0,
marketPosition: 0,
lastPrice: 0,
holdPrice: 0,
holdAmount: 0,
holdProfit: 0,
switchCount: 0,
N: 0,
upLine: 0,
downLine: 0,
lastErr: "",
lastErrTime: "",
stopPrice: '',
leavePrice: '',
isTrading: false
};
obj.setLastError = function(err) {
if (typeof(err) === 'undefined' || err === '') {
obj.status.lastErr = "";
obj.status.lastErrTime = "";
return;
}
var t = new Date();
obj.status.lastErr = err;
obj.status.lastErrTime = t.toLocaleString();
};
obj.reset = function(marketPosition, openPrice, N, leavePeriod, preBreakoutFailure) {
if (typeof(marketPosition) !== 'undefined') {
obj.marketPosition = marketPosition;
obj.openPrice = openPrice;
obj.preBreakoutFailure = preBreakoutFailure;
obj.N = N;
obj.leavePeriod = leavePeriod;
var pos = _q.GetPosition(exchange, obj.tradeSymbol, marketPosition > 0 ? PD_LONG : PD_SHORT);
if (pos) {
obj.holdPrice = pos.Price;
obj.holdAmount = pos.Amount;
Log(obj.symbol, "仓位", pos);
} else {
throw "恢复" + obj.symbol + "的持仓状态出错, 没有找到仓位信息";
}
Log("恢复", obj.symbol, "加仓次数", obj.marketPosition, "持仓均价:", obj.holdPrice, "持仓数量:", obj.holdAmount, "最后一次加仓价", obj.openPrice, "N值", obj.N, "离市周期:", leavePeriod, "上次突破:", obj.preBreakoutFailure ? "失败" : "成功");
obj.status.open = 1;
obj.status.vm = [obj.marketPosition, obj.openPrice, obj.N, obj.leavePeriod, obj.preBreakoutFailure];
} else {
obj.marketPosition = 0;
obj.holdPrice = 0;
obj.openPrice = 0;
obj.holdAmount = 0;
obj.holdProfit = 0;
obj.preBreakoutFailure = true; // test system A
obj.N = 0;
obj.leavePeriod = leavePeriodA;
}
obj.holdProfit = 0;
obj.lastErr = "";
obj.lastErrTime = "";
};
obj.Status = function() {
obj.status.N = obj.N;
obj.status.marketPosition = obj.marketPosition;
obj.status.holdPrice = obj.holdPrice;
obj.status.holdAmount = obj.holdAmount;
obj.status.lastPrice = obj.lastPrice;
if (obj.lastPrice > 0 && obj.holdAmount > 0 && obj.marketPosition !== 0) {
obj.status.holdProfit = _N((obj.lastPrice - obj.holdPrice) * obj.holdAmount * obj.symbolDetail.VolumeMultiple, 4) * (obj.marketPosition > 0 ? 1 : -1);
} else {
obj.status.holdProfit = 0;
}
obj.status.symbolDetail = obj.symbolDetail;
return obj.status;
};
obj.Poll = function() {
obj.status.isTrading = $.IsTrading(obj.symbol);
if (!obj.status.isTrading) {
return;
}
// busy
if (_q.hasTask(obj.tradeSymbol)) {
return
}
// Loop
var suffix = WXPush ? '@' : '';
// switch symbol
var insDetail = exchange.SetContractType(obj.symbol);
if (!insDetail) {
return
}
var records = exchange.GetRecords();
if (!records) {
obj.setLastError("获取K线失败");
return;
}
// update tradeSymbol
var tradeSymbol = insDetail.InstrumentID;
if (tradeSymbol != obj.tradeSymbol) {
var oldSymbol = obj.tradeSymbol;
var pos = _q.GetPosition(exchange, oldSymbol);
if (pos && pos.Amount > 0) {
Log("开始移仓", oldSymbol, "->", tradeSymbol, "数量:", pos.Amount, "#ff0000");
obj.status.switchCount++;
_q.pushTask(exchange, oldSymbol, (pos.Type == PD_LONG ? "closebuy" : "closesell"), pos.Amount, function(task, ret) {
if (!ret) {
Log(oldSymbol, "移仓平仓失败 #ff0000");
return;
}
Log("移仓进度平仓成功, 开始开仓", oldSymbol, "->", tradeSymbol, "数量:", pos.Amount, "#0000ff");
obj.tradeSymbol = tradeSymbol;
obj.symbolDetail = insDetail;
_q.pushTask(exchange, tradeSymbol, (pos.Type == PD_LONG ? "buy" : "sell"), pos.Amount, function(task, ret) {
if (!ret) {
Log(tradeSymbol, "移仓开仓失败, 重置品种进度 #ff0000");
obj.marketPosition = 0;
return;
}
Log("移仓成功", oldSymbol, "->", tradeSymbol, "#0000ff");
});
});
return;
} else {
obj.tradeSymbol = tradeSymbol;
obj.symbolDetail = insDetail;
}
}
obj.status.recordsLen = records.length;
if (records.length < obj.atrLen) {
obj.setLastError("K线长度小于 " + obj.atrLen);
return;
}
var opCode = 0; // 0: IDLE, 1: LONG, 2: SHORT, 3: CoverALL
var lastPrice = records[records.length - 1].Close;
obj.lastPrice = lastPrice;
if (obj.marketPosition === 0) {
obj.status.stopPrice = '--';
obj.status.leavePrice = '--';
obj.status.upLine = 0;
obj.status.downLine = 0;
for (var i = 0; i < 2; i++) {
if (i == 0 && obj.useFilter && !obj.preBreakoutFailure) {
continue;
}
var enterPeriod = i == 0 ? obj.enterPeriodA : obj.enterPeriodB;
if (records.length < (enterPeriod + 1)) {
continue;
}
var highest = TA.Highest(records, enterPeriod, 'High');
var lowest = TA.Lowest(records, enterPeriod, 'Low');
obj.status.upLine = obj.status.upLine == 0 ? highest : Math.min(obj.status.upLine, highest);
obj.status.downLine = obj.status.downLine == 0 ? lowest : Math.max(obj.status.downLine, lowest);
if (lastPrice > highest) {
opCode = 1;
} else if (lastPrice < lowest) {
opCode = 2;
}
if (opCode != 0) {
obj.leavePeriod = (enterPeriod == obj.enterPeriodA) ? obj.leavePeriodA : obj.leavePeriodB;
break;
}
}
} else {
var spread = obj.marketPosition > 0 ? (obj.openPrice - lastPrice) : (lastPrice - obj.openPrice);
obj.status.stopPrice = _N(obj.openPrice + (obj.N * StopLossRatio * (obj.marketPosition > 0 ? -1 : 1)));
if (spread > (obj.N * StopLossRatio)) {
opCode = 3;
obj.preBreakoutFailure = true;
Log(obj.symbolDetail.InstrumentName, "止损平仓", suffix);
obj.status.st++;
} else if (-spread > (IncSpace * obj.N) && Math.abs(obj.marketPosition) < obj.maxLots) {
opCode = obj.marketPosition > 0 ? 1 : 2;
}
if (opCode == 0 && records.length > obj.leavePeriod) {
obj.status.leavePrice = obj.marketPosition > 0 ? TA.Lowest(records, obj.leavePeriod, 'Low') : TA.Highest(records, obj.leavePeriod, 'High');
if ((obj.marketPosition > 0 && lastPrice < obj.status.leavePrice) ||
(obj.marketPosition < 0 && lastPrice > obj.status.leavePrice)) {
obj.preBreakoutFailure = false;
Log(obj.symbolDetail.InstrumentName, "正常平仓", suffix);
opCode = 3;
obj.status.cover++;
}
}
}
if (opCode == 0) {
return;
}
if (opCode == 3) {
_q.pushTask(exchange, obj.tradeSymbol, "coverall", 0, function(task, ret) {
obj.reset();
_G(obj.symbol, null);
var account = _q.GetAccount(exchange);
var accountInfo = JSON.parse(exchange.GetRawJSON());
LogProfit(accountInfo.Balance, obj.tradeSymbol, "平仓后权益");
});
return;
}
// Open
if (Math.abs(obj.marketPosition) >= obj.maxLots) {
obj.setLastError("禁止开仓, 超过最大持仓 " + obj.maxLots);
return;
}
var atrs = TA.ATR(records, atrLen);
var N = _N(atrs[atrs.length - 1], 4);
var account = _q.GetAccount(exchange);
var unit = parseInt((obj.initBalance-obj.keepBalance) * (obj.riskRatio / 100) / N / obj.symbolDetail.VolumeMultiple);
var canOpen = parseInt((account.Balance-obj.keepBalance) / (opCode == 1 ? obj.symbolDetail.LongMarginRatio : obj.symbolDetail.ShortMarginRatio) / (lastPrice * 1.2) / obj.symbolDetail.VolumeMultiple);
unit = Math.min(unit, canOpen);
if (unit < obj.symbolDetail.MinLimitOrderVolume) {
obj.setLastError("可开 " + unit + " 手 无法开仓, " + (canOpen >= obj.symbolDetail.MinLimitOrderVolume ? "风控触发" : "资金限制") + "可用: " + account.Balance);
return;
}
_q.pushTask(exchange, obj.tradeSymbol, (opCode == 1 ? "buy" : "sell"), unit, function(task, ret) {
if (!ret) {
obj.setLastError("下单失败");
return;
}
Log(obj.symbolDetail.InstrumentName, obj.marketPosition == 0 ? "开仓" : "加仓", "离市周期", obj.leavePeriod, suffix);
obj.N = N;
obj.openPrice = ret.price;
obj.holdPrice = ret.position.Price;
if (obj.marketPosition == 0) {
obj.status.open++;
}
obj.holdAmount = ret.position.Amount;
obj.marketPosition += opCode == 1 ? 1 : -1;
obj.status.vm = [obj.marketPosition, obj.openPrice, N, obj.leavePeriod, obj.preBreakoutFailure];
_G(obj.symbol, obj.status.vm);
});
};
var vm = null;
if (RMode === 0) {
vm = _G(obj.symbol);
} else {
vm = JSON.parse(VMStatus)[obj.symbol];
}
if (vm) {
Log("准备恢复进度, 当前合约状态为", vm);
obj.reset(vm[0], vm[1], vm[2], vm[3], vm[4]);
} else {
if (needRestore) {
Log("没有找到" + obj.symbol + "的进度恢复信息");
}
obj.reset();
}
return obj;
}
};
function onexit() {
Log("已退出策略...");
}
function main() {
if (exchange.GetName().indexOf('CTP') == -1) {
throw "只支持商品期货CTP";
}
SetErrorFilter("login|ready|流控|连接失败|初始|Timeout");
var mode = exchange.IO("mode", 0);
if (typeof(mode) !== 'number') {
throw "切换模式失败, 请更新到最新托管者!";
}
while (!exchange.IO("status")) {
Sleep(3000);
LogStatus("正在等待与交易服务器连接, " + _D());
}
var positions = _C(exchange.GetPosition);
if (positions.length > 0) {
Log("检测到当前持有仓位, 系统将开始尝试恢复进度...");
Log("持仓信息", positions);
}
Log("风险系数:", RiskRatio, "N值周期:", ATRLength, "系统1: 入市周期", EnterPeriodA, "离市周期", LeavePeriodA, "系统二: 入市周期", EnterPeriodB, "离市周期", LeavePeriodB, "加仓系数:", IncSpace, "止损系数:", StopLossRatio, "单品种最多开仓:", MaxLots, "次");
var initAccount = _q.GetAccount(exchange);
var initMargin = JSON.parse(exchange.GetRawJSON()).CurrMargin;
var realInitBalance = initAccount.Balance + initMargin;
if (CustomBalance) {
realInitBalance = InitBalance;
Log("自定义启动资产为", realInitBalance);
}
var keepBalance = _N(realInitBalance * (KeepRatio/100), 3);
Log("当前资产信息", initAccount, "保留资金:", keepBalance);
var tts = [];
var filter = [];
var arr = Instruments.split(',');
for (var i = 0; i < arr.length; i++) {
var symbol = arr[i].replace(/^\s+/g, "").replace(/\s+$/g, "");
if (typeof(filter[symbol]) !== 'undefined') {
Log(symbol, "已经存在, 系统已自动过滤");
continue;
}
filter[symbol] = true;
var hasPosition = false;
for (var j = 0; j < positions.length; j++) {
if (positions[j].ContractType == symbol) {
hasPosition = true;
break;
}
}
var obj = TTManager.New(hasPosition, symbol, realInitBalance, keepBalance, RiskRatio, ATRLength, EnterPeriodA, LeavePeriodA, EnterPeriodB, LeavePeriodB, UseEnterFilter, IncSpace, StopLossRatio, MaxLots);
tts.push(obj);
}
var lastStatus = '';
while (true) {
if (GetCommand() === "暂停/继续") {
Log("暂停交易中...");
while (GetCommand() !== "暂停/继续") {
Sleep(1000);
}
Log("继续交易中...");
}
while (!exchange.IO("status")) {
Sleep(3000);
LogStatus("正在等待与交易服务器连接, " + _D() + "\n" + lastStatus);
}
var tblStatus = {
type: "table",
title: "持仓信息",
cols: ["合约名称", "持仓方向", "持仓均价", "持仓数量", "持仓盈亏", "加仓次数", "开仓次数", "止损次数", "成功次数", "当前价格", "N"],
rows: []
};
var tblMarket = {
type: "table",
title: "运行状态",
cols: ["合约名称", "合约乘数", "保证金率", "交易时间", "移仓次数", "柱线长度", "上线", "下线", "止损价", "离市价", "异常描述", "发生时间"],
rows: []
};
var totalHold = 0;
var vmStatus = {};
var ts = new Date().getTime();
var holdSymbol = 0;
for (var i = 0; i < tts.length; i++) {
tts[i].Poll();
var d = tts[i].Status();
if (d.holdAmount > 0) {
vmStatus[d.symbol] = d.vm;
holdSymbol++;
}
tblStatus.rows.push([d.symbolDetail.InstrumentID, d.holdAmount == 0 ? '--' : (d.marketPosition > 0 ? '多' : '空'), d.holdPrice, d.holdAmount, d.holdProfit, Math.abs(d.marketPosition), d.open, d.st, d.cover, d.lastPrice, d.N]);
tblMarket.rows.push([d.symbolDetail.InstrumentID, d.symbolDetail.VolumeMultiple, _N(d.symbolDetail.LongMarginRatio, 4) + '/' + _N(d.symbolDetail.ShortMarginRatio, 4), (d.isTrading ? '是#0000ff' : '否#ff0000'), d.switchCount, d.recordsLen, d.upLine, d.downLine, d.stopPrice, d.leavePrice, d.lastErr, d.lastErrTime]);
totalHold += Math.abs(d.holdAmount);
}
var now = new Date();
var elapsed = now.getTime() - ts;
var tblAssets = _q.GetAccount(exchange, true);
var nowAccount = _q.Account();
if (tblAssets.rows.length > 10) {
// replace AccountId
tblAssets.rows[0] = ["InitAccount", "初始资产", realInitBalance];
} else {
tblAssets.rows.unshift(["NowAccount", "当前可用", nowAccount], ["InitAccount", "初始资产", realInitBalance]);
}
if (totalHold > 0) {
tblAssets.rows.push(["手动恢复字符串", {body:JSON.stringify(vmStatus), colspan: 2}]);
}
lastStatus = '`' + JSON.stringify([tblStatus, tblMarket, tblAssets]) + '`\n轮询耗时: ' + elapsed + ' 毫秒, 当前时间: ' + _D() + ', 星期' + ['日', '一', '二', '三', '四', '五', '六'][now.getDay()] + ", 持有品种个数: " + holdSymbol + ", 交易任务: " + _q.size();
LogStatus(lastStatus);
_q.poll();
Sleep(LoopInterval * 1000);
}
}
```
> 策略出处
https://www.fmz.com/strategy/17289
> 更新时间
2020-04-17 13:30:40
+345
View File
@@ -0,0 +1,345 @@
> 策略名称
多平台对冲稳定套利
> 策略作者
John
> 策略描述
程序自动换算汇率,手续费,下单参考买一卖一的价,注意这个不是搬砖,是对冲! 不需要人工转钱或者币,一个存钱,一个存币,一个买,一个卖,高级对冲模式.
这种对冲模式不管币的价格是涨还是跌,只赚差价。
建仓需要一个放钱,一个放币,比如BTC现在价格6000吧,一个交易所放3000刀,一个放0.45左右得币就行了,或者全部加倍
MaxDiff指最低平台差价
SlidePrice指下单时的滑动价, 买单就加上这个价, 卖单就减去这个价
TickIntervalS 指检测周期
跌停值指币跌到这个价格了就不操作,涨停值指币高于这个价格也不操作,防止平台恶意给机器人下套.
> 策略参数
|参数|默认值|描述|
|----|----|----|
|Interval|500|出错重试间隔(毫秒)|
|TickInterval|300|检测频率(毫秒)|
|MaxDiff|3|最低差价(元)|
|SlidePrice|0.1|止损滑动价(元)|
|SlideRatio|2|对冲滑动价系数|
|StopPriceL|1000|跌停值(元)|
|StopPriceH|9000|涨停值(元)|
|optFeeTimeout|30|手续费更新周期(分)|
|AmountOnce|0.2|单笔交易数量|
|UseMarketOrder|false|使用市价单止损|
|StopWhenLoss|false|亏损时停止|
|MaxLoss|50|最大亏损限度(元)|
|SMSAPI|http://|短信通知接口|
> 源码 (javascript)
``` javascript
var initState;
var isBalance = true;
var feeCache = new Array();
var feeTimeout = optFeeTimeout * 60000;
var lastProfit = 0;
var lastAvgPrice = 0;
var lastSpread = 0;
var lastOpAmount = 0;
function adjustFloat(v) {
return Math.floor(v * 1000) / 1000;
}
function isPriceNormal(v) {
return (v >= StopPriceL) && (v <= StopPriceH);
}
function stripTicker(t) {
return 'Buy: ' + adjustFloat(t.Buy) + ' Sell: ' + adjustFloat(t.Sell);
}
function updateStatePrice(state) {
var now = (new Date()).getTime();
for (var i = 0; i < state.details.length; i++) {
var ticker = null;
var key = state.details[i].exchange.GetName() + state.details[i].exchange.GetCurrency();
var fee = null;
while (!(ticker = state.details[i].exchange.GetTicker())) {
Sleep(Interval);
}
if (key in feeCache) {
var v = feeCache[key];
if ((now - v.time) > feeTimeout) {
delete feeCache[key];
} else {
fee = v.fee;
}
}
if (!fee) {
while (!(fee = state.details[i].exchange.GetFee())) {
Sleep(Interval);
}
feeCache[key] = {
fee: fee,
time: now
};
}
// Buy-=fee Sell+=fee
state.details[i].ticker = {
Buy: ticker.Buy * (1 - (fee.Sell / 100)),
Sell: ticker.Sell * (1 + (fee.Buy / 100))
};
state.details[i].realTicker = ticker;
state.details[i].fee = fee;
}
}
function getProfit(stateInit, stateNow, coinPrice) {
var netNow = stateNow.allBalance + (stateNow.allStocks * coinPrice);
var netInit = stateInit.allBalance + (stateInit.allStocks * coinPrice);
return adjustFloat(netNow - netInit);
}
function getExchangesState() {
var allStocks = 0;
var allBalance = 0;
var minStock = 0;
var details = [];
for (var i = 0; i < exchanges.length; i++) {
var account = null;
while (!(account = exchanges[i].GetAccount())) {
Sleep(Interval);
}
allStocks += account.Stocks + account.FrozenStocks;
allBalance += account.Balance + account.FrozenBalance;
minStock = Math.max(minStock, exchanges[i].GetMinStock());
details.push({
exchange: exchanges[i],
account: account
});
}
return {
allStocks: adjustFloat(allStocks),
allBalance: adjustFloat(allBalance),
minStock: minStock,
details: details
};
}
function cancelAllOrders() {
for (var i = 0; i < exchanges.length; i++) {
while (true) {
var orders = null;
while (!(orders = exchanges[i].GetOrders())) {
Sleep(Interval);
}
if (orders.length == 0) {
break;
}
for (var j = 0; j < orders.length; j++) {
exchanges[i].CancelOrder(orders[j].Id, orders[j]);
}
}
}
}
function balanceAccounts() {
// already balance
if (isBalance) {
return;
}
cancelAllOrders();
var state = getExchangesState();
var diff = state.allStocks - initState.allStocks;
var adjustDiff = adjustFloat(Math.abs(diff));
if (adjustDiff < state.minStock) {
isBalance = true;
} else {
Log('初始币总数量:', initState.allStocks, '现在币总数量: ', state.allStocks, '差额:', adjustDiff);
// other ways, diff is 0.012, bug A only has 0.006 B only has 0.006, all less then minstock
// we try to statistical orders count to recognition this situation
updateStatePrice(state);
var details = state.details;
var ordersCount = 0;
if (diff > 0) {
var attr = 'Sell';
if (UseMarketOrder) {
attr = 'Buy';
}
// Sell adjustDiff, sort by price high to low
details.sort(function(a, b) {
return b.ticker[attr] - a.ticker[attr];
});
for (var i = 0; i < details.length && adjustDiff >= state.minStock; i++) {
if (isPriceNormal(details[i].ticker[attr]) && (details[i].account.Stocks >= state.minStock)) {
var orderAmount = adjustFloat(Math.min(AmountOnce, adjustDiff, details[i].account.Stocks));
var orderPrice = details[i].realTicker[attr] - SlidePrice;
if ((orderPrice * orderAmount) < details[i].exchange.GetMinPrice()) {
continue;
}
ordersCount++;
if (details[i].exchange.Sell(orderPrice, orderAmount, stripTicker(details[i].ticker))) {
adjustDiff = adjustFloat(adjustDiff - orderAmount);
}
// only operate one platform
break;
}
}
} else {
var attr = 'Buy';
if (UseMarketOrder) {
attr = 'Sell';
}
// Buy adjustDiff, sort by sell-price low to high
details.sort(function(a, b) {
return a.ticker[attr] - b.ticker[attr];
});
for (var i = 0; i < details.length && adjustDiff >= state.minStock; i++) {
if (isPriceNormal(details[i].ticker[attr])) {
var canRealBuy = adjustFloat(details[i].account.Balance / (details[i].ticker[attr] + SlidePrice));
var needRealBuy = Math.min(AmountOnce, adjustDiff, canRealBuy);
var orderAmount = adjustFloat(needRealBuy * (1 + (details[i].fee.Buy / 100)));
var orderPrice = details[i].realTicker[attr] + SlidePrice;
if ((orderAmount < details[i].exchange.GetMinStock()) ||
((orderPrice * orderAmount) < details[i].exchange.GetMinPrice())) {
continue;
}
ordersCount++;
if (details[i].exchange.Buy(orderPrice, orderAmount, stripTicker(details[i].ticker))) {
adjustDiff = adjustFloat(adjustDiff - needRealBuy);
}
// only operate one platform
break;
}
}
}
isBalance = (ordersCount == 0);
}
if (isBalance) {
var currentProfit = getProfit(initState, state, lastAvgPrice);
LogProfit(currentProfit, "Spread: ", adjustFloat((currentProfit - lastProfit) / lastOpAmount), "Balance: ", adjustFloat(state.allBalance), "Stocks: ", adjustFloat(state.allStocks));
if (StopWhenLoss && currentProfit < 0 && Math.abs(currentProfit) > MaxLoss) {
Log('交易亏损超过最大限度, 程序取消所有订单后退出.');
cancelAllOrders();
if (SMSAPI.length > 10 && SMSAPI.indexOf('http') == 0) {
HttpQuery(SMSAPI);
Log('已经短信通知');
}
throw '已停止';
}
lastProfit = currentProfit;
}
}
function onTick() {
if (!isBalance) {
balanceAccounts();
return;
}
var state = getExchangesState();
// We also need details of price
updateStatePrice(state);
var details = state.details;
var maxPair = null;
var minPair = null;
for (var i = 0; i < details.length; i++) {
var sellOrderPrice = details[i].account.Stocks * (details[i].realTicker.Buy - SlidePrice);
if (((!maxPair) || (details[i].ticker.Buy > maxPair.ticker.Buy)) && (details[i].account.Stocks >= state.minStock) &&
(sellOrderPrice > details[i].exchange.GetMinPrice())) {
details[i].canSell = details[i].account.Stocks;
maxPair = details[i];
}
var canBuy = adjustFloat(details[i].account.Balance / (details[i].realTicker.Sell + SlidePrice));
var buyOrderPrice = canBuy * (details[i].realTicker.Sell + SlidePrice);
if (((!minPair) || (details[i].ticker.Sell < minPair.ticker.Sell)) && (canBuy >= state.minStock) &&
(buyOrderPrice > details[i].exchange.GetMinPrice())) {
details[i].canBuy = canBuy;
// how much coins we real got with fee
details[i].realBuy = adjustFloat(details[i].account.Balance / (details[i].ticker.Sell + SlidePrice));
minPair = details[i];
}
}
if ((!maxPair) || (!minPair) || ((maxPair.ticker.Buy - minPair.ticker.Sell) < MaxDiff) ||
!isPriceNormal(maxPair.ticker.Buy) || !isPriceNormal(minPair.ticker.Sell)) {
return;
}
// filter invalid price
if (minPair.realTicker.Sell <= minPair.realTicker.Buy || maxPair.realTicker.Sell <= maxPair.realTicker.Buy) {
return;
}
// what a fuck...
if (maxPair.exchange.GetName() == minPair.exchange.GetName()) {
return;
}
lastAvgPrice = adjustFloat((minPair.realTicker.Buy + maxPair.realTicker.Buy) / 2);
lastSpread = adjustFloat((maxPair.realTicker.Sell - minPair.realTicker.Buy) / 2);
// compute amount
var amount = Math.min(AmountOnce, maxPair.canSell, minPair.realBuy);
lastOpAmount = amount;
var hedgePrice = adjustFloat((maxPair.realTicker.Buy - minPair.realTicker.Sell) / Math.max(SlideRatio, 2))
if (minPair.exchange.Buy(minPair.realTicker.Sell + hedgePrice, amount * (1 + (minPair.fee.Buy / 100)), stripTicker(minPair.realTicker))) {
maxPair.exchange.Sell(maxPair.realTicker.Buy - hedgePrice, amount, stripTicker(maxPair.realTicker));
}
isBalance = false;
}
function main() {
if (exchanges.length < 2) {
throw "交易所数量最少得两个才能完成对冲";
}
TickInterval = Math.max(TickInterval, 50);
Interval = Math.max(Interval, 50);
cancelAllOrders();
initState = getExchangesState();
if (initState.allStocks == 0) {
throw "所有交易所货币数量总和为空, 必须先在任一交易所建仓才可以完成对冲";
}
if (initState.allBalance == 0) {
throw "所有交易所CNY数量总和为空, 无法继续对冲";
}
for (var i = 0; i < initState.details.length; i++) {
var e = initState.details[i];
Log(e.exchange.GetName(), e.exchange.GetCurrency(), e.account);
}
Log("ALL: Balance: ", initState.allBalance, "Stocks: ", initState.allStocks, "Ver:", Version());
while (true) {
onTick();
Sleep(parseInt(TickInterval));
}
}
```
> 策略出处
https://www.fmz.com/strategy/194150
> 更新时间
2020-04-15 14:13:49
@@ -0,0 +1,398 @@
> 策略名称
币安永续多币种对冲策略原版(做多超跌做空超涨)4月13日最新止损模块
> 策略作者
小草
> 策略描述
## 4.16日更新内容
更改了止损的bug
修改了默认参数:
```
var Alpha = 0.001 //指数移动平均的Alpha参数,设置的越大,基准价格跟踪越敏感,最终持仓也会越低,降低了杠杆,但会降低收益,具体需要根据回测结果自己权衡
var Update_base_price_time_interval = 60 //多久更新一次基准价格, 单位秒,和Alpha参数相关,Alpha 设置的越小,这个间隔也可以设置的更小
```
## 4.13 更新内容
Stop_loss设置为0.8表示当资金达到低于初始资金的80%时,止损,清空所有仓位,停止策略。随着策略运行,Stop_loss可以设置大于1(重启生效),比如从1000赚到1500,Stop_loss设置为1.3,则回撤到1300元止损。不想止损可以把这个参数设置的很小。风险是大家都用这种止损会形成踩踏,加大亏损。初始资金在状态栏的init_balance字段,注意提现等操作会影响,别不小心止损了。如果还是怕黑天鹅事件,比如某个币归0等,可以手动提现出来。
Max_diff和Min_diff限制了偏离的程度,需要根据自己的trade_value,总资金和风险承受能力自己确定。
举个简单例子,假如一共交易20个币,其中一个币价值逐渐上涨到偏离0.4不再交易,其它币价格一直不变会,亏损trade_value的7倍。不断下跌到偏离到偏离-0.3,将亏损trade_value的6倍。
```
var Stop_loss = 0.8
var Max_diff = 0.4 //当偏差diff大于0.4时,不继续加空仓, 自行设置
var Min_diff = -0.3 //当diff小于-0.3时,不继续加多仓, 自行设置
```
## 4.10 更新内容
**把策略代码复制到本地策略,直接覆盖保存即可,重启机器人生效,还会保持原有的仓位**
币安期货做空超涨做多超跌策略重要优化notebook代码地址:https://www.fmz.com/bbs-topic/5364
原有策略山寨币指数 = mean(sum((山寨币价格/比特币价格)/(山寨币初始价格/比特币初始价格)))。最大的问题是最新价格和策略启动的初始价格对比,随着时间的增长,会越来越偏离,一个币可能持有很多的仓位,风险很高,最后将持有很多仓位,增加了风险和回撤。
最新的山寨币指数 = mean(sum((山寨币价格/比特币价格)/EMA(山寨币价格/比特币价格))),即是和均线的价格进行对比,能够跟踪最新的价格变化,更加灵活,回测发现降低了策略持仓,也减少了回撤。更加稳定。最重要的是原策略如果加入几个异常交易对,风险极高,很可能爆仓,现在却几乎不受影响。
为了无缝升级,其中两个参数写到了策略代码的前两行,按需更改。
Alpha = 0.04 指数移动平局的Alpha参数,设置的越大,基准价格跟踪越敏感,交易的越少,最终持仓也会越低,降低了杠杆,但会降低收益,降低最大回撤,可以加大成交量,具体需要根据回测结果自己权衡。
Update_base_price_time_interval = 30*60 多久更新一次基准价格, 单位秒,和Alpha参数相关,Alpha 设置的越小,这个间隔也可以设置的更小
如果你看了文章,想要交易全币种,这里是列表``ETH,BCH,XRP,EOS,LTC,TRX,ETC,LINK,XLM,ADA,XMR,DASH,ZEC,XTZ,BNB,ATOM,ONT,IOTA,BAT,VET,NEO,QTUM,IOST``
## **重要内容!!**
- 一定要先看这篇研究 https://www.fmz.com/digest-topic/5294 。了解策略原理、风险、交易对如何筛选、如何设置参数、开仓和总资金的比例等等一系列问题。
- 上一篇研究报告需要下载并上传到自己的研究环境中。实际修改运行一遍。如果你已经看过这篇报告,最近又更新了最新一周的数据。
- **策略不能直接回测,需要在研究环境中回测**。
- 策略代码以及默认参数仅供研究,实盘运行需要谨慎,根据自己的研究决定参数,**自担风险**。
- **策略不可能每天盈利,可看回测历史,1-2周的横盘和回撤都是正常的,需要正确对待**
- 代码是公开的,可以自行修改,如果有任何问题,欢迎评论反馈,最好加入发明者币安交流群(研究报告中有加入方法),可获得更新通知
- **策略仅支持币安期货,需要在全仓模式运行,不要设置双向持仓!!,创建机器人时用默认交易对和K线周期即可,策略没有用到K线**
- **策略和其他策略以及手动操作是冲突的,需要注意**
- 实盘运行需要海外托管者,测试阶段可在平台一键租用阿里云香港服务器,自己按月整租更便宜(配置最低的即可,部署教程:https://www.fmz.com/bbs-topic/2848)
- 币安的期货和现货需要单独添加,币安期货为``Futures_Binance``
- 此策略重启不影响,但是新建机器人会重新记录历史数据。
- 策略根据用户反馈可能会有更新,直接ctrl+A复制代码覆盖保存(一般不会更新参数),重启机器人即可用上最新代码。
- 策略一开始并不会交易,第一次启动需要记录数据,需要等待行情的变化才会交易
## 加入微信群参加币安千团大战获取更新
加下方微信号,回复“币安”即自动拉入群:
https://www.fmz.com![IMG](https://www.fmz.com/upload/asset/1fbed0c3795dbecac04.jpg)
## 策略原理
将做空价格高于山寨币-比特币价格指数的币种,做多低于指数的币种,偏离越大,仓位越大。(本策略没有把不对等的仓位用BTC对冲,也可以把BTC加入交易对)。最近两个月的表现(3倍左右杠杆,数据更新到4.8):
![IMG](https://www.fmz.com/upload/asset/1b2a6f297fcf590ad02.png)
## 策略逻辑
1.更新行情和账户持仓,第一次运行会记录初始价格(新加入的币种按照加入时间计算)
2.更新指数,指数是山寨币-比特币价格指数 = mean(sum((山寨币价格/比特币价格)/(山寨币初始价格/比特币初始价格)))
3.根据偏离指数判断做多做空,根据偏离大小判断仓位
4.下单,下单量由冰山委托决定,按照对手价成交(买入用卖一价)。**下单后立即撤销(所以会看到很多撤销失败的单子400: {"code":-2011,"msg":"Unknown order sent."},正常现象)**
5.再次循环
状态栏中的leverage代表保证金已用占比,需要保持较低水平以满足新的开仓
## 策略参数
![IMG](https://www.fmz.com/upload/asset/272b24a9c0018c96fb6.png)
- Trade_symbols:交易的币种,需要自己根据研究平台自己筛选,也可以加入BTC
- Trade_value:山寨币价格(BTC计价)每偏离指数1%持有价值,需要根据自己投入的总资金和风险偏好决定,建议设置为总资金的3-10%。可通过研究环境的回测看杠杆的大小,Trade_value可以小于Adjust_value,如Adjust_value的一半,这样相当于偏离指数2%的持有价值。
- Adjust_value: 合约价值(USDT计价)调整偏离值。 当 指数偏离 \* Trade_value - 当前持仓 > Adjust_value,即目标持仓和当前持仓的差超过此值,就会开始交易。过大调整较慢,太小交易频繁,不能低于10,否则会达不到最小成交,推荐设置为Trade_value的40%以上。
- Ice_value:冰山委托价值,同样不能低于10,实际下单选Adjust_value与Ice_value 中较小的那一个,如果资金较多可以设置的相对大一些这样调整的更快,建议不低于Adjust_value的20%,这样5次冰山就能完成成交,当然,Trade_value不大时,Ice_value可以设置的相对大一下,一两次就能调整到位。
- Interval:循环休眠时间,可以设置的小一些,如1s,但不能超过币安频率限制。
- Reset:重置历史数据,会将策略参考的初始价格重新设置为当前的价格,一般不用设置
## 策略风险
注意到如果某个币走出了独立的行情,比如相对于指数上涨了几倍,将会在该币种上积累大量的做空仓位,同样的大幅下跌也会使得策略大量做多。可限制开仓量或者止损不再交易。
> 策略参数
|参数|默认值|描述|
|----|----|----|
|Trade_symbols|IOST,TRX,XLM,QTUM,DASH,ADA,BNB,XMR,ZEC,ATOM,IOTA,NEO,ONT,XRP,BAT,VET,EOS,ETC,LTC|交易的币种|
|Trade_value|20|每偏离指数1%持有价值|
|Adjust_value|20|合约价值调整偏离值|
|Ice_value|20|冰山委托订单的大小|
|Log_profit_interval|600|Log总权益间隔s|
|Interval|true|休眠时间s|
|Reset|false|重置历史数据|
> 源码 (javascript)
``` javascript
var Alpha = 0.001 //指数移动平均的Alpha参数,设置的越大,基准价格跟踪越敏感,最终持仓也会越低,降低了杠杆,但会降低收益,具体需要根据回测结果自己权衡
var Update_base_price_time_interval = 60 //多久更新一次基准价格, 单位秒,和Alpha参数相关,Alpha 设置的越小,这个间隔也可以设置的更小
//Stop_loss设置为0.8表示当资金达到低于初始资金的80%时,止损,清空所有仓位,停止策略。
//随着策略运行,Stop_loss可以设置大于1(重启生效),比如从1000赚到1500,Stop_loss设置为1.3,则回撤到1300元止损。不想止损可以把这个参数设置的很小。
//风险是大家都用这种止损会形成踩踏,加大亏损。
//初始资金在状态栏的init_balance字段,注意提现等操作会影响,别不小心止损了。
//如果还是怕黑天鹅事件,比如某个币归0等,可以手动提现出来。
var Stop_loss = 0.8
var Max_diff = 0.4 //当偏差diff大于0.4时,不继续加空仓, 自行设置
var Min_diff = -0.3 //当diff小于-0.3时,不继续加多仓, 自行设置
if(IsVirtual()){
throw '不能回测,回测参考 https://www.fmz.com/digest-topic/5294 '
}
if(exchange.GetName() != 'Futures_Binance'){
throw '只支持币安期货交易所,和现货交易所不同,需要单独添加,名称为Futures_Binance'
}
var trade_symbols = Trade_symbols.split(',')
var symbols = trade_symbols
var index = 1 //指数
if(trade_symbols.indexOf('BTC')<0){
symbols = trade_symbols.concat(['BTC'])
}
var update_profit_time = 0
var update_base_price_time= Date.now()
var assets = {}
var init_prices = {}
var trade_info = {}
var exchange_info = HttpQuery('https://fapi.binance.com/fapi/v1/exchangeInfo')
if(!exchange_info){
throw '无法连接币安网络,需要海外托管者'
}
exchange_info = JSON.parse(exchange_info)
for (var i=0; i<exchange_info.symbols.length; i++){
if(symbols.indexOf(exchange_info.symbols[i].baseAsset) > -1){
assets[exchange_info.symbols[i].baseAsset] = {amount:0, hold_price:0, value:0, bid_price:0, ask_price:0,
btc_price:0, btc_change:1,btc_diff:0,
realised_profit:0, margin:0, unrealised_profit:0}
trade_info[exchange_info.symbols[i].baseAsset] = {minQty:parseFloat(exchange_info.symbols[i].filters[1].minQty),
priceSize:parseInt((Math.log10(1.1/parseFloat(exchange_info.symbols[i].filters[0].tickSize)))),
amountSize:parseInt((Math.log10(1.1/parseFloat(exchange_info.symbols[i].filters[1].stepSize))))
}
}
}
assets.USDT = {unrealised_profit:0, margin:0, margin_balance:0, total_balance:0, leverage:0, update_time:0, init_balance:0, stop_balance:0, profit:0}
function updateAccount(){ //更新账户和持仓
var account = exchange.GetAccount()
var pos = exchange.GetPosition()
if (account == null || pos == null ){
Log('update account time out')
return
}
assets.USDT.update_time = Date.now()
for(var i=0; i<trade_symbols.length; i++){
assets[trade_symbols[i]].margin = 0
assets[trade_symbols[i]].unrealised_profit = 0
assets[trade_symbols[i]].hold_price = 0
assets[trade_symbols[i]].amount = 0
}
for(var j=0; j<account.Info.positions.length; j++){
if(account.Info.positions[j].positionSide == 'BOTH'){
var pair = account.Info.positions[j].symbol
var coin = pair.slice(0,pair.length-4)
if(symbols.indexOf(coin) < 0){continue}
assets[coin].margin = parseFloat(account.Info.positions[j].initialMargin) + parseFloat(account.Info.positions[j].maintMargin)
assets[coin].unrealised_profit = parseFloat(account.Info.positions[j].unrealizedProfit)
}
}
assets.USDT.margin = _N(parseFloat(account.Info.totalInitialMargin) + parseFloat(account.Info.totalMaintMargin),2)
assets.USDT.margin_balance = _N(parseFloat(account.Info.totalMarginBalance),2)
assets.USDT.total_balance = _N(parseFloat(account.Info.totalWalletBalance),2)
if(assets.USDT.init_balance == 0){
if(_G('init_balance')){
assets.USDT.init_balance = _N(_G('init_balance'),2)
}else{
assets.USDT.init_balance = assets.USDT.total_balance
_G('init_balance',assets.USDT.init_balance)
}
}
assets.USDT.stop_balance = _N(Stop_loss*assets.USDT.init_balance, 2)
assets.USDT.total_balance = _N(parseFloat(account.Info.totalWalletBalance),2)
assets.USDT.unrealised_profit = _N(parseFloat(account.Info.totalUnrealizedProfit),2)
assets.USDT.leverage = _N(assets.USDT.margin/assets.USDT.total_balance,2)
pos = JSON.parse(exchange.GetRawJSON())
if(pos.length > 0){
for(var k=0; k<pos.length; k++){
var pair = pos[k].symbol
var coin = pair.slice(0,pair.length-4)
if(symbols.indexOf(coin) < 0){continue}
if(pos[k].positionSide != 'BOTH'){continue}
assets[coin].hold_price = parseFloat(pos[k].entryPrice)
assets[coin].amount = parseFloat(pos[k].positionAmt)
assets[coin].unrealised_profit = parseFloat(pos[k].unRealizedProfit)
}
}
}
function updateIndex(){ //更新指数
if(!_G('init_prices') || Reset){
Reset = false
for(var i=0; i<trade_symbols.length; i++){
init_prices[trade_symbols[i]] = (assets[trade_symbols[i]].ask_price+assets[trade_symbols[i]].bid_price)/(assets.BTC.ask_price+assets.BTC.bid_price)
}
Log('保存启动时的价格')
_G('init_prices',init_prices)
}else{
init_prices = _G('init_prices')
if(Date.now() - update_base_price_time > Update_base_price_time_interval*1000){
update_base_price_time = Date.now()
for(var i=0; i<trade_symbols.length; i++){ //更新初始价格
init_prices[trade_symbols[i]] = init_prices[trade_symbols[i]]*(1-Alpha)+Alpha*(assets[trade_symbols[i]].ask_price+assets[trade_symbols[i]].bid_price)/(assets.BTC.ask_price+assets.BTC.bid_price)
}
_G('init_prices',init_prices)
//Log(init_prices)
//Log('更新了一次基准价格')
}
var temp = 0
for(var i=0; i<trade_symbols.length; i++){
assets[trade_symbols[i]].btc_price = (assets[trade_symbols[i]].ask_price+assets[trade_symbols[i]].bid_price)/(assets.BTC.ask_price+assets.BTC.bid_price)
if(!(trade_symbols[i] in init_prices)){
Log('添加新的币种',trade_symbols[i])
init_prices[trade_symbols[i]] = assets[trade_symbols[i]].btc_price
_G('init_prices',init_prices)
}
assets[trade_symbols[i]].btc_change = _N(assets[trade_symbols[i]].btc_price/init_prices[trade_symbols[i]],4)
temp += assets[trade_symbols[i]].btc_change
}
index = _N(temp/trade_symbols.length, 4)
}
}
function updateTick(){ //更新行情
var ticker = HttpQuery('https://fapi.binance.com/fapi/v1/ticker/bookTicker')
try {
ticker = JSON.parse(ticker)
}catch(e){
Log('get ticker time out')
return
}
for(var i=0; i<ticker.length; i++){
var pair = ticker[i].symbol
var coin = pair.slice(0,pair.length-4)
if(symbols.indexOf(coin) < 0){continue}
assets[coin].ask_price = parseFloat(ticker[i].askPrice)
assets[coin].bid_price = parseFloat(ticker[i].bidPrice)
assets[coin].ask_value = _N(assets[coin].amount*assets[coin].ask_price, 2)
assets[coin].bid_value = _N(assets[coin].amount*assets[coin].bid_price, 2)
}
updateIndex()
for(var i=0; i<trade_symbols.length; i++){
assets[trade_symbols[i]].btc_diff = _N(assets[trade_symbols[i]].btc_change - index, 4)
}
}
function trade(symbol, dirction, value){ //交易
if(Date.now()-assets.USDT.update_time > 10*1000){
Log('更新账户延时,不交易')
return
}
var price = dirction == 'sell' ? assets[symbol].bid_price : assets[symbol].ask_price
var amount = _N(Math.min(value,Ice_value)/price, trade_info[symbol].amountSize)
if(amount < trade_info[symbol].minQty){
Log(symbol, '合约价值偏离或冰山委托订单的大小设置过小,达不到最小成交, 至少需要: ', _N(trade_info[symbol].minQty*price,0)+1)
return
}
exchange.IO("currency", symbol+'_'+'USDT')
exchange.SetContractType('swap')
exchange.SetDirection(dirction)
var f = dirction == 'buy' ? 'Buy' : 'Sell'
var id = exchange[f](price, amount, symbol)
if(id){
exchange.CancelOrder(id) //订单会立即撤销
}
return id
}
function updateStatus(){ //状态栏信息
var table = {type: 'table', title: '交易对信息',
cols: ['币种', '数量', '持仓价格', '当前价格', '偏离平均', '持仓价值', '保证金', '未实现盈亏'],
rows: []}
for (var i=0; i<symbols.length; i++){
var price = _N((assets[symbols[i]].ask_price + assets[symbols[i]].bid_price)/2, trade_info[symbols[i]].priceSize)
var value = _N((assets[symbols[i]].ask_value + assets[symbols[i]].bid_value)/2, 2)
var infoList = [symbols[i], assets[symbols[i]].amount, assets[symbols[i]].hold_price, price, assets[symbols[i]].btc_diff, value, _N(assets[symbols[i]].margin,3), _N(assets[symbols[i]].unrealised_profit,3)]
table.rows.push(infoList)
}
var logString = _D() + ' ' + JSON.stringify(assets.USDT) + ' Index:' + index + '\n'
LogStatus(logString + '`' + JSON.stringify(table) + '`')
if(Date.now()-update_profit_time > Log_profit_interval*1000){
LogProfit(_N(assets.USDT.margin_balance,3))
update_profit_time = Date.now()
}
}
function stopLoss(){ //止损函数
while(true){
if(assets.USDT.margin_balance < Stop_loss*assets.USDT.init_balance && assets.USDT.init_balance > 0){
Log('触发止损,当前资金:', assets.USDT.margin_balance, '初始资金:', assets.USDT.init_balance)
Ice_value = 200 //止损的快一些,可修改
updateAccount()
updateTick()
var trading = false //是否正在交易
for(var i=0; i<trade_symbols.length; i++){
var symbol = trade_symbols[i]
if(assets[symbol].ask_price == 0){ continue }
if(assets[symbol].bid_value >= trade_info[symbol].minQty*assets[symbol].bid_price){
trade(symbol, 'sell', assets[symbol].bid_value)
trading = true
}
if(assets[symbol].ask_value <= -trade_info[symbol].minQty*assets[symbol].ask_price){
trade(symbol, 'buy', -assets[symbol].ask_value)
trading = true
}
}
Sleep(1000)
if(!trading){
throw '止损结束,如果需要重新运行策略,需要调低止损'
}
}else{ //不用止损
return
}
}
}
function onTick(){ //策略逻辑部分
for(var i=0; i<trade_symbols.length; i++){
var symbol = trade_symbols[i]
if(assets[symbol].ask_price == 0){ continue }
var aim_value = -Trade_value * _N(assets[symbol].btc_diff/0.01,3)
if(aim_value - assets[symbol].ask_value >= Adjust_value && assets[symbol].btc_diff > Min_diff){
trade(symbol,'buy', aim_value - assets[symbol].ask_value)
}
if(aim_value - assets[symbol].bid_value <= -Adjust_value && assets[symbol].btc_diff < Max_diff){
trade(symbol,'sell', -(aim_value - assets[symbol].bid_value))
}
}
}
function main() {
while(true){
updateAccount()
updateTick()
stopLoss() //止损
onTick()
updateStatus()
Sleep(Interval*1000)
}
}
```
> 策略出处
https://www.fmz.com/strategy/195226
> 更新时间
2020-04-16 17:33:37
@@ -0,0 +1,266 @@
> 策略名称
币安永续多币种对冲策略(做空或做多山寨币指数)4月10日改进Bug,需要更新
> 策略作者
小草
> 策略描述
## **重要内容!!**
- 一定要先看这篇研究 https://www.fmz.com/digest-topic/5294 。了解策略原理、风险、交易对如何筛选、如何设置参数、开仓和总资金的比例等等一系列问题。
- 上一篇研究报告需要下载并上传到自己的研究环境中。实际修改运行一遍。如果你已经看过这篇报告,最近又更新了最新一周的数据。
- **策略不能直接回测,需要在研究环境中回测**。
- 策略代码以及默认参数仅供研究,实盘运行需要谨慎,根据自己的研究决定参数,**自担风险**。
- **策略不可能每天盈利,可看回测历史,1-2周的横盘和回撤都是正常的,并且有可能回测很大,需要正确对待**
- 代码是公开的,可以自行修改,如果有任何问题,欢迎评论反馈,最好加入发明者币安交流群(研究报告中有加入方法),可获得更新通知
- **策略需要在全仓模式运行,不要设置双向持仓,策略只支持币安期货,创建机器人时用默认交易对和K线周期即可,策略没有用到K线**
- **策略和其他策略以及手动操作是冲突的,需要注意**
- 实盘运行需要海外托管者,测试阶段可在平台一键租用阿里云香港服务器,自己按月整租更便宜(配置最低的即可,部署教程: https://www.fmz.com/bbs-topic/2848 )
- 币安的期货和现货需要单独添加,币安期货为``Futures_Binance``
## 策略原理
策略将分散等值做空选定的一篮子山寨币,同时等仓位做多比特币对冲,降低风险和波动率。随着价格的波动,不断调整仓位保持空头价值恒定和多头仓位对等。**本质上时做空山寨币-比特币价格指数**。最近两个月的表现(3倍左右杠杆,数据更新到4.8),最近一周山寨币相对于比特币是上涨的,因此亏损,如果你看多山寨币,可以在参数中设置做空比特币做多山寨币:
**策略默认是做多比特币做空山寨币,你也可以反过来(假如你认为山寨币处于底部),决定权在自己**
![IMG](https://www.fmz.com/upload/asset/24281c6de45544ca2b7.png)
## 策略逻辑
1.更新行情和账户持仓
2.更新各个山寨币空头持仓价值,判断空头是否需要调整持仓
3.更新总空头的仓位,确定多头持仓,判断多头仓位是否要调整
4.下单,下单量由冰山委托决定,按照对手价成交(买入用卖一价)。**下单后立即撤销(所以会看到很多撤销失败的单子400: {"code":-2011,"msg":"Unknown order sent."},正常现象)**
5.再次循环
**会判断Short_symbols,Long_symbols那个交易对多,多的每个币种开仓价值为Trade_value,少的每个币种合约价值为需要对冲价值的平均。**
如果只空BTC,多TRX,DASH,ONT,QTUM,Trade_value为50,则TRX,DASH,ONT,QTUM均有多仓50,BTC持有空仓50\*4。
如果只多BTC,空TRX,DASH,ONT,QTUM,Trade_value为50,则TRX,DASH,ONT,QTUM均有空仓50,BTC持有多仓50\*4。
状态栏中的leverage代表保证金已用占比,不宜过高。
## 策略参数
![IMG](https://www.fmz.com/upload/asset/2c9e5e0e4c30f9eaada.png)
- Short_symbols:做空的币种,用“ , ”隔开
- Long_symbols:做多的币种,也可以留空,不对冲,直接裸空。
- Trade_value:单个币种做空持有价值。还要做多对冲,总价值=2\*Trade_value\*做空币种数。一般使用3-5倍杠杆,即总价值=3*账户余额。需要根据自己投入的总资金决定,可通过研究环境的回测看杠杆的大小
- Adjust_value: 合约价值(USDT计价)调整偏离值,过大调整较慢,太小手续费过高,根据Trade_value自行决定。不能低于20,否则会达不到最小成交
- Ice_value:冰山委托价值,同样不能低于20,实际下单选Adjust_value与Ice_value 中较小的那一个
## 策略风险
当做空的币价上涨,合约价值增加,此时是减仓的,反之盈利是加仓。这使得总的合约价值维持恒定。山寨币是很有可能走出独立的行情的,目前从一年的周期看,山寨币可能处于底部,并且有可能从底部抬升不少。这取决与如何使用,如果你看好山寨币并认为已经到底部,可以方向操作,做多指数。或者你看好某几个币种(不一定是比特币),可以和它们对冲。
> 策略参数
|参数|默认值|描述|
|----|----|----|
|Short_symbols|TRX,DASH,ONT,QTUM,BAT,IOST,ADA,ZEC,XMR,NEO,VET,XRP,IOTA,XLM|做空的交易对|
|Long_symbols|BTC|做多的交易对|
|Trade_value|50|做空的单个合约价值|
|Adjust_value|20|合约价值调整偏离值|
|Ice_value|50|冰山委托订单的大小|
|Log_profit_interval|20|Log总权益间隔s|
|Interval|5|休眠时间s|
> 源码 (javascript)
``` javascript
if(IsVirtual()){
throw '不能回测,回测参考 https://www.fmz.com/digest-topic/5294 '
}
if(exchange.GetName() != 'Futures_Binance'){
throw '只支持币安期货交易所,和现货交易所不同,需要单独添加,名称为Futures_Binance'
}
var short_symbols = Short_symbols.split(',')
var long_symbols = Long_symbols.split(',')
var symbols = short_symbols.concat(long_symbols)
var update_profit_time = 0
var assets = {}
var trade_info = {}
var exchange_info = HttpQuery('https://fapi.binance.com/fapi/v1/exchangeInfo')
if(!exchange_info){
throw '无法连接币安网络,需要海外托管者'
}
exchange_info = JSON.parse(exchange_info)
for (var i=0; i<exchange_info.symbols.length; i++){
if(symbols.indexOf(exchange_info.symbols[i].baseAsset) > -1){
assets[exchange_info.symbols[i].baseAsset] = {amount:0, hold_price:0, value:0, bid_price:0, ask_price:0, realised_profit:0, margin:0, unrealised_profit:0}
trade_info[exchange_info.symbols[i].baseAsset] = {minQty:parseFloat(exchange_info.symbols[i].filters[1].minQty),
priceSize:parseInt((Math.log10(1.1/parseFloat(exchange_info.symbols[i].filters[0].tickSize)))),
amountSize:parseInt((Math.log10(1.1/parseFloat(exchange_info.symbols[i].filters[1].stepSize))))
}
}
}
assets.USDT = {unrealised_profit:0, margin:0, margin_balance:0, total_balance:0, leverage:0}
function updateAccount(){
var account = exchange.GetAccount()
var pos = exchange.GetPosition()
if (account == null || pos == null ){
Log('update account time out')
return
}
assets.USDT.update_time = Date.now()
for(var i=0; i<symbols.length; i++){
assets[symbols[i]].margin = 0
assets[symbols[i]].unrealised_profit = 0
assets[symbols[i]].hold_price = 0
assets[symbols[i]].amount = 0
assets[symbols[i]].unrealised_profit = 0
}
for(var j=0; j<account.Info.positions.length; j++){
var pair = account.Info.positions[j].symbol
var coin = pair.slice(0,pair.length-4)
if(symbols.indexOf(coin) < 0){continue}
assets[coin].margin = parseFloat(account.Info.positions[j].initialMargin) + parseFloat(account.Info.positions[j].maintMargin)
assets[coin].unrealised_profit = parseFloat(account.Info.positions[j].unrealizedProfit)
}
assets.USDT.margin = _N(parseFloat(account.Info.totalInitialMargin) + parseFloat(account.Info.totalMaintMargin),2)
assets.USDT.margin_balance = _N(parseFloat(account.Info.totalMarginBalance),2)
assets.USDT.total_balance = _N(parseFloat(account.Info.totalWalletBalance),2)
assets.USDT.unrealised_profit = _N(parseFloat(account.Info.totalUnrealizedProfit),2)
assets.USDT.leverage = _N(assets.USDT.margin/assets.USDT.total_balance,2)
pos = JSON.parse(exchange.GetRawJSON())
if(pos.length > 0){
for(var k=0; k<pos.length; k++){
var pair = pos[k].symbol
var coin = pair.slice(0,pair.length-4)
if(symbols.indexOf(coin) < 0){continue}
assets[coin].hold_price = parseFloat(pos[k].entryPrice)
assets[coin].amount = parseFloat(pos[k].positionAmt)
assets[coin].unrealised_profit = parseFloat(pos[k].unRealizedProfit)
}
}
}
function updateTick(){
var ticker = HttpQuery('https://fapi.binance.com/fapi/v1/ticker/bookTicker')
if(ticker == null){
Log('get ticker time out')
return
}
ticker = JSON.parse(ticker)
for(var i=0; i<ticker.length; i++){
var pair = ticker[i].symbol
var coin = pair.slice(0,pair.length-4)
if(symbols.indexOf(coin) < 0){continue}
assets[coin].ask_price = parseFloat(ticker[i].askPrice)
assets[coin].bid_price = parseFloat(ticker[i].bidPrice)
assets[coin].ask_value = _N(assets[coin].amount*assets[coin].ask_price, 2)
assets[coin].bid_value = _N(assets[coin].amount*assets[coin].bid_price, 2)
}
}
function trade(symbol, dirction, value){
if(Date.now()-assets.USDT.update_time > 10*1000){
Log('更新账户延时,不交易')
return
}
var price = dirction == 'sell' ? assets[symbol].bid_price : assets[symbol].ask_price
var amount = _N(Math.min(value,Ice_value)/price, trade_info[symbol].amountSize)
if(amount < trade_info[symbol].minQty){
Log(symbol, '合约调整偏离价值或冰山委托订单设置过小,达不到最小成交, 至少需要: ', _N(trade_info[symbol].minQty*price,0))
return
}
exchange.IO("currency", symbol+'_'+'USDT')
exchange.SetContractType('swap')
exchange.SetDirection(dirction)
var f = dirction == 'buy' ? 'Buy' : 'Sell'
var id = exchange[f](price, amount, symbol)
if(id){
exchange.CancelOrder(id) //订单会立即撤销
}
}
function updateStatus(){
var table = {type: 'table', title: '交易对信息',
cols: ['币种', '数量', '持仓价格', '当前价格', '持仓价值', '保证金', '未实现盈亏'],
rows: []}
for (var i=0; i<symbols.length; i++){
var price = _N((assets[symbols[i]].ask_price + assets[symbols[i]].bid_price)/2, trade_info[symbols[i]].priceSize)
var value = _N((assets[symbols[i]].ask_value + assets[symbols[i]].bid_value)/2, 2)
var infoList = [symbols[i], assets[symbols[i]].amount, assets[symbols[i]].hold_price, price, value,_N(assets[symbols[i]].margin,3), _N(assets[symbols[i]].unrealised_profit,3)]
table.rows.push(infoList)
}
var logString = _D() + ' ' + JSON.stringify(assets.USDT) + '\n'
LogStatus(logString + '`' + JSON.stringify(table) + '`')
if(Date.now()-update_profit_time > Log_profit_interval*1000){
LogProfit(_N(assets.USDT.margin_balance,3))
update_profit_time = Date.now()
}
}
function onTick(){
var short_value = Trade_value
if(short_symbols.length<long_symbols.length){
short_value = _N(long_symbols.length*Trade_value/short_symbols.length,0)
}
var long_value = Trade_value
if(short_symbols.length>long_symbols.length){
long_value = _N(short_symbols.length*Trade_value/long_symbols.length,0)
}
var symbol = ''
for(var i=0; i<short_symbols.length; i++){
symbol = short_symbols[i]
if(assets[symbol].ask_price == 0){ continue }
if(assets[symbol].bid_value + short_value > Adjust_value){
trade(symbol, 'sell', assets[symbol].bid_value + short_value)
}
if(assets[symbol].ask_value + short_value < -Adjust_value){
trade(symbol, 'buy', -(assets[symbol].ask_value + short_value))
}
}
for(var i=0; i<long_symbols.length; i++){
symbol = long_symbols[i]
if(assets[symbol].ask_price == 0){ continue }
if(assets[symbol].bid_value - long_value > Adjust_value){
trade(symbol, 'sell', assets[symbol].bid_value-long_value)
}
if(assets[symbol].ask_value - long_value < -Adjust_value){
trade(symbol, 'buy', long_value-assets[symbol].ask_value)
}
}
}
function main() {
while(true){
updateAccount()
updateTick()
onTick()
updateStatus()
Sleep(Interval*1000)
}
}
```
> 策略出处
https://www.fmz.com/strategy/194825
> 更新时间
2020-04-14 23:02:44
+309
View File
@@ -0,0 +1,309 @@
> 策略名称
币安策略二去掉高低分
> 策略作者
tomjava
> 策略描述
感谢FMZ公开策略,感谢卫兵支持!
本人做了两项修改:
1、因为很多朋友默认都是10倍,20倍杠杆,而该策略为全仓模式,一个币爆仓,就会被团灭。所以加上了一个Max_amount,单个币种买入量不会超过这个数,防止爆仓
2、如果币池里有超涨超跌,特例独行的币,容易把大家拖下水,整体策略容易失效。因此我计算指数时去掉一个最高分,去掉一个最低分,得出的指数更公平。
等特例独行的币恢复正常,还是可以正常买入的。
注意:因条件所限,本策略未经回测,仅供参考,如有损失,概不负责!
## **重要内容!!**
- 一定要先看这篇研究 https://www.fmz.com/digest-topic/5294 。了解策略原理、风险、交易对如何筛选、如何设置参数、开仓和总资金的比例等等一系列问题。
- 上一篇研究报告需要下载并上传到自己的研究环境中。实际修改运行一遍。如果你已经看过这篇报告,最近又更新了最新一周的数据。
- **策略不能直接回测,需要在研究环境中回测**。
- 策略代码以及默认参数仅供研究,实盘运行需要谨慎,自担风险。
- 代码是公开的,可以自行修改,如果有任何问题,欢迎评论反馈,最好加入发明者币安交流群(研究报告中有加入方法)
- 策略需要在全仓模式运行,**策略支持币安,创建机器人时用默认交易对和K线周期即可,策略没有用到K线**
## 策略原理
将做空价格高于山寨币-比特币价格指数的币种,做多低于指数的币种,偏离越大,仓位越大。(本策略没有对冲,也可以把BTC加入交易对)。最近两个月的表现(3倍左右杠杆,数据更新到4.8):
![IMG](https://www.fmz.com/upload/asset/2546f22f018c51604db.png)
## 策略逻辑
1.更新行情和账户持仓,第一次运行会记录初始价格(新加入的币种按照加入时间计算)
2.更新指数,指数是山寨币-比特币价格指数 = mean(sum((山寨币价格/比特币价格)/(山寨币初始价格/比特币初始价格)))
3.根据偏离指数判断做多做空,根据偏离大小判断仓位
4.下单,下单量由冰山委托决定,按照对手价成交(买入用卖一价)。**下单后立即撤销(所以会看到很多撤销失败的单子,正常)**
5.再次循环
## 策略参数
![IMG](https://www.fmz.com/upload/asset/272b24a9c0018c96fb6.png)
- Trade_symbols:交易的币种,需要自己根据研究平台自己筛选,也可以加入BTC
- Trade_value:山寨币做空持有价值,需要根据自己投入的总资金决定,可通过研究环境的回测看杠杆的大小
- Adjust_value: 合约价值(USDT计价)调整偏离值,过大调整较慢,不能低于20,否则会达不到最小成交
- Ice_value:冰山委托价值,同样不能低于20,实际下单选Adjust_value/Ice_value 中较小的那一个
- Reset:重置历史数据
## 策略风险
注意到如果某个币走出了独立的行情,比如相对于指数上涨了几倍,将会在该币种上积累大量的做空仓位,同样的大幅下跌也会使得策略大量做多。可限制开仓量或者止损不再交易。
> 策略参数
|参数|默认值|描述|
|----|----|----|
|Trade_symbols|IOST,TRX,XLM,QTUM,DASH,ADA,XMR,ZEC,ATOM,IOTA,NEO,ONT,XRP,VET,EOS,ETC,LTC|交易的币种|
|Trade_value|50|每偏离指数1%持有价值|
|Adjust_value|20|合约价值调整偏离值|
|Ice_value|20|冰山委托订单的大小|
|Log_profit_interval|600|Log总权益间隔s|
|Interval|5|休眠时间s|
|Reset|false|重置历史数据|
|Max_amount|300|最大成交量,超过则不买入|
> 源码 (javascript)
``` javascript
//向上偏离最大的币的索引
var highIndex=0;
//向下偏离最大的币的索引
var lowIndex=0;
var trade_symbols = Trade_symbols.split(',')
var symbols = trade_symbols
var index = 1 //指数
if(trade_symbols.indexOf('BTC')<0){
symbols = trade_symbols.concat(['BTC'])
}
var update_profit_time = 0
var assets = {}
var trade_info = {}
var exchange_info = HttpQuery('https://fapi.binance.com/fapi/v1/exchangeInfo')
if(!exchange_info){
Log('无法连接网络')
return
}
exchange_info = JSON.parse(exchange_info)
for (var i=0; i<exchange_info.symbols.length; i++){
if(symbols.indexOf(exchange_info.symbols[i].baseAsset) > -1){
assets[exchange_info.symbols[i].baseAsset] = {amount:0, hold_price:0, value:0, bid_price:0, ask_price:0,
btc_price:0, btc_change:1,btc_diff:0,
realised_profit:0, margin:0, unrealised_profit:0}
trade_info[exchange_info.symbols[i].baseAsset] = {minQty:parseFloat(exchange_info.symbols[i].filters[1].minQty),
priceSize:parseInt((Math.log10(1.1/parseFloat(exchange_info.symbols[i].filters[0].tickSize)))),
amountSize:parseInt((Math.log10(1.1/parseFloat(exchange_info.symbols[i].filters[1].stepSize))))
}
}
}
assets.USDT = {unrealised_profit:0, margin:0, margin_balance:0, total_balance:0, leverage:0, update_time:0}
function updateAccount(){ //更新账户和持仓
var account = exchange.GetAccount()
var pos = exchange.GetPosition()
if (account == null || pos == null ){
Log('update account time out')
return
}
assets.USDT.update_time = Date.now()
for(var i=0; i<trade_symbols.length; i++){
assets[trade_symbols[i]].margin = 0
assets[trade_symbols[i]].unrealised_profit = 0
assets[trade_symbols[i]].hold_price = 0
assets[trade_symbols[i]].amount = 0
assets[trade_symbols[i]].unrealised_profit = 0
}
for(var j=0; j<account.Info.positions.length; j++){
var pair = account.Info.positions[j].symbol
var coin = pair.slice(0,pair.length-4)
if(symbols.indexOf(coin) < 0){continue}
assets[coin].margin = parseFloat(account.Info.positions[j].initialMargin) + parseFloat(account.Info.positions[j].maintMargin)
assets[coin].unrealised_profit = parseFloat(account.Info.positions[j].unrealizedProfit)
}
assets.USDT.margin = _N(parseFloat(account.Info.totalInitialMargin) + parseFloat(account.Info.totalMaintMargin),2)
assets.USDT.margin_balance = _N(parseFloat(account.Info.totalMarginBalance),2)
assets.USDT.total_balance = _N(parseFloat(account.Info.totalWalletBalance),2)
assets.USDT.unrealised_profit = _N(parseFloat(account.Info.totalUnrealizedProfit),2)
assets.USDT.leverage = _N(assets.USDT.margin/assets.USDT.total_balance,2)
if(pos.length > 0){
pos = JSON.parse(exchange.GetRawJSON())
for(var k=0; k<pos.length; k++){
var pair = pos[k].symbol
var coin = pair.slice(0,pair.length-4)
if(symbols.indexOf(coin) < 0){continue}
assets[coin].hold_price = parseFloat(pos[k].entryPrice)
assets[coin].amount = parseFloat(pos[k].positionAmt)
assets[coin].unrealised_profit = parseFloat(pos[k].unRealizedProfit)
}
}
}
function updateIndex(){ //更新指数
var init_prices = {}
if(!_G('init_prices') || Reset){
for(var i=0; i<trade_symbols.length; i++){
init_prices[trade_symbols[i]] = (assets[trade_symbols[i]].ask_price+assets[trade_symbols[i]].bid_price)/(assets.BTC.ask_price+assets.BTC.bid_price)
}
Log('保存启动时的价格')
_G('init_prices',init_prices)
}else{
init_prices = _G('init_prices')
var temp = 0
highIndex=0;
lowIndex=0;
var highChange;var lowChange;
//本次计算找出最大偏离的高低分
for(var i=0; i<trade_symbols.length; i++){
assets[trade_symbols[i]].btc_price = (assets[trade_symbols[i]].ask_price+assets[trade_symbols[i]].bid_price)/(assets.BTC.ask_price+assets.BTC.bid_price)
if(!init_prices[trade_symbols[i]]){
Log('添加新的币种',trade_symbols[i])
init_prices[trade_symbols[i]] = assets[trade_symbols[i]].btc_price
_G('init_prices',init_prices)
}
assets[trade_symbols[i]].btc_change = _N(assets[trade_symbols[i]].btc_price/init_prices[trade_symbols[i]],4)
if(i==0){
highChange=assets[trade_symbols[i]].btc_change;
lowChange=assets[trade_symbols[i]].btc_change;
}
if(highChange<assets[trade_symbols[i]].btc_change){
highChange=assets[trade_symbols[i]].btc_change;
highIndex=i;
}
if(lowChange>assets[trade_symbols[i]].btc_change){
lowChange=assets[trade_symbols[i]].btc_change;
lowIndex=i;
}
}
for(var i=0; i<trade_symbols.length; i++){
assets[trade_symbols[i]].btc_price = (assets[trade_symbols[i]].ask_price+assets[trade_symbols[i]].bid_price)/(assets.BTC.ask_price+assets.BTC.bid_price)
assets[trade_symbols[i]].btc_change = _N(assets[trade_symbols[i]].btc_price/init_prices[trade_symbols[i]],4)
if(i!=lowIndex&&i!=highIndex){ //去掉高低分的影响
temp += assets[trade_symbols[i]].btc_change
}
}
//因为去掉了最高最低分,所以减2
index = _N(temp/(trade_symbols.length-2), 4)
}
}
function updateTick(){ //更新行情
var ticker = HttpQuery('https://fapi.binance.com/fapi/v1/ticker/bookTicker')
try {
ticker = JSON.parse(ticker)
}catch(e){
Log('get ticker time out')
return
}
for(var i=0; i<ticker.length; i++){
var pair = ticker[i].symbol
var coin = pair.slice(0,pair.length-4)
if(symbols.indexOf(coin) < 0){continue}
assets[coin].ask_price = parseFloat(ticker[i].askPrice)
assets[coin].bid_price = parseFloat(ticker[i].bidPrice)
assets[coin].ask_value = _N(assets[coin].amount*assets[coin].ask_price, 2)
assets[coin].bid_value = _N(assets[coin].amount*assets[coin].bid_price, 2)
}
updateIndex()
for(var i=0; i<trade_symbols.length; i++){
assets[trade_symbols[i]].btc_diff = _N(assets[trade_symbols[i]].btc_change - index, 4)
}
}
function trade(symbol, dirction, value){ //交易
if(Date.now()-assets.USDT.update_time > 10*1000){
Log('更新账户延时,不交易')
return
}
var price = dirction == 'sell' ? assets[symbol].bid_price : assets[symbol].ask_price
var amount = _N(Math.min(value,Ice_value)/price, trade_info[symbol].amountSize)
if(amount <= trade_info[symbol].minQty){
Log(symbol, '合约价值偏离或冰山委托订单的大小设置过小,达不到最小成交, 至少需要: ', _N(trade_info[symbol].minQty*price,0))
return
}
exchange.IO("currency", symbol+'_'+'USDT')
exchange.SetContractType('swap')
exchange.SetDirection(dirction)
var f = dirction == 'buy' ? 'Buy' : 'Sell'
var id = exchange[f](price, amount, symbol)
if(id){
exchange.CancelOrder(id) //订单会立即撤销
}
}
function updateStatus(){ //状态栏信息
var table = {type: 'table', title: '交易对信息更新',
cols: ['Symbol', 'amount', 'hold_price', 'price', 'diff', 'value', 'margin', 'unrealised_profit'],
rows: []}
var infoList;
for (var i=0; i<symbols.length; i++){
var price = _N((assets[symbols[i]].ask_price + assets[symbols[i]].bid_price)/2, trade_info[symbols[i]].priceSize)
var value = _N((assets[symbols[i]].ask_value + assets[symbols[i]].bid_value)/2, 2)
if(i==lowIndex){
infoList = [symbols[i]+"Low", assets[symbols[i]].amount, assets[symbols[i]].hold_price, price, assets[symbols[i]].btc_diff, value, _N(assets[symbols[i]].margin,3), _N(assets[symbols[i]].unrealised_profit,3)]
}else if(i==highIndex){
infoList = [symbols[i]+"High", assets[symbols[i]].amount, assets[symbols[i]].hold_price, price, assets[symbols[i]].btc_diff, value, _N(assets[symbols[i]].margin,3), _N(assets[symbols[i]].unrealised_profit,3)]
}else{
infoList = [symbols[i], assets[symbols[i]].amount, assets[symbols[i]].hold_price, price, assets[symbols[i]].btc_diff, value, _N(assets[symbols[i]].margin,3), _N(assets[symbols[i]].unrealised_profit,3)]
}
table.rows.push(infoList)
}
var logString = _D() + ' ' + JSON.stringify(assets.USDT) + ' Index:' + index + '\n'
LogStatus(logString + '`' + JSON.stringify(table) + '`')
if(Date.now()-update_profit_time > Log_profit_interval*1000){
LogProfit(_N(assets.USDT.margin_balance,3))
update_profit_time = Date.now()
}
}
function onTick(){ //策略逻辑部分
for(var i=0; i<trade_symbols.length; i++){
var symbol = trade_symbols[i]
if(assets[symbol].ask_price == 0){ continue }
var aim_value = -Trade_value * _N(assets[symbol].btc_diff/0.01,1)
if(i!=lowIndex&&i!=highIndex){ //高低分的货币不交易
if(aim_value - assets[symbol].ask_value > Adjust_value&&assets[symbol].ask_value<Max_amount){
trade(symbol,'buy', aim_value - assets[symbol].ask_value)
}
if(aim_value - assets[symbol].bid_value < -Adjust_value&&assets[symbol].bid_value<Max_amount){
trade(symbol,'sell', -(aim_value - assets[symbol].bid_value))
}
}
}
}
function main() {
while(true){
updateAccount()
updateTick()
onTick()
updateStatus()
Sleep(Interval*1000)
}
}
```
> 策略出处
https://www.fmz.com/strategy/196445
> 更新时间
2020-04-09 21:51:18
-190
View File
@@ -1,190 +0,0 @@
> 策略名称
暴雪网格-7*24小时交易机器人
> 策略作者
红色的雪
> 策略参数
|参数|默认值|描述|
|----|----|----|
|base_price|3|基础价格-中线价格|
|sale_buy_diff|0.03|买卖差价,卖出的价格- 买入的价格|
|two_distance|0.01|递增、递减的时候,每个格子的距离|
|trade_amount|2|每次交易的数量|
|sale_price_max|5|卖出的上限价格|
|buy_price_min|true|买入的上限价格|
> 源码 (python)
``` python
#!python2
# -*- coding:utf-8 -*-
'''
主要是使用发明者量化API进行网格买卖,当前只支持单品网格买卖
'''
from time import sleep
import datetime,copy
sale_price_list = [] #卖出的价格列表
buy_price_list = [] #买入的价格列表
class fmz_market():
def get_data_depth(self):
data_depth = exchange.GetDepth()
return data_depth
#检查当前是否可以进行买卖操作
def make_trade_check(self,symbol):
trade_infor = {'price':0,'trade_type':''}
#进行买卖列表判断,先更新交易记录列表
trade_price_list = self.get_trade_price_list(symbol)
sale_price_list = trade_price_list[0]
buy_price_list = trade_price_list[1]
#获取深度数据
data_depth = self.get_data_depth()
#买单列表:
data_depth_bids = data_depth.Bids[0]
#卖单列表:
data_depth_asks = data_depth.Asks[0]
#如果买入记录不为空
sale_buy_diff_now = two_distance*len(sale_price_list) if len(sale_price_list) >0 else sale_buy_diff
sale_buy_diff_sale = two_distance if len(sale_price_list) > 0 else sale_buy_diff
# sale_price_last = float(sale_price_list[len(sale_price_list)-1]) if len(sale_price_list) >0 else base_price
# buy_price_last = float(buy_price_list[len(buy_price_list)-1]) if len(buy_price_list) >0 else base_price
sale_price_last = float(sale_price_list[0]) if len(sale_price_list) > 0 and float(sale_price_list[0]) > base_price else base_price
buy_price_last = float(buy_price_list[0]) if len(buy_price_list) > 0 and float(buy_price_list[0]) < base_price else base_price
#判断当前价格是否满足 卖出的价格请求
if float(data_depth_bids.Price) - sale_price_last > sale_buy_diff_sale and float(data_depth_bids.Amount) > trade_amount * 1.5:
Log("当前卖价:",str(data_depth_bids.Price),"订单中最高卖价:",str(sale_price_last),"生成卖单")
trade_infor['price'] = float(data_depth_bids.Price)
trade_infor['trade_type'] = 'sale'
#判断当前价格是否满足 买入的价格请求
if buy_price_last - float(data_depth_asks.Price) > sale_buy_diff_now and float(data_depth_bids.Amount) > trade_amount * 1.5:
#Log("当前买价:", str(data_depth_asks.Price), "订单中最高买价:", str(sale_price_last),"生成买单")
trade_infor['price'] = float(data_depth_bids.Price)
trade_infor['trade_type'] = 'buy'
#判断当前价格是否破格,破格则置空买卖信息
if float(data_depth_bids.Price) - sale_price_max > 0 or buy_price_min - float(data_depth_asks.Price) > 0:
trade_infor['price'] = 0
trade_infor['trade_type'] = ''
timestr = (datetime.datetime.now()).strftime('%Y-%m-%d %H:%M:%S')
Log(trade_infor,"...time:",timestr)
if trade_infor['price'] != 0:
#Log(trade_infor,"...time:",timestr)
pass
return trade_infor
#根据委托信息生成买卖价格列表
def get_trade_price_list(self,symbol):
sale_list = []
buy_list = []
#获取所有的交易记录,根据不同的类型 分配到 买卖列表中
orders = exchange.GetOrders()
for i in range(len(orders)):
if orders[i].Type == 1:
sale_price = float(orders[i].Price)
sale_price_bak = copy.deepcopy(sale_price)
sale_list.append(sale_price_bak)
if orders[i].Type == 0:
buy_price = float(orders[i].Price)
buy_price_bak = copy.deepcopy(buy_price)
buy_list.append(buy_price_bak)
#判断为0的数组进处理
if len(sale_list) == 0:
for i in range(len(buy_list)):
sale_list.append(float('%.6f' % (buy_list[i] + sale_buy_diff)))
if len(buy_list) == 0:
for i in range(len(sale_list)):
buy_list.append(float('%.6f' % (sale_list[i] - sale_buy_diff)))
trade_price_list = [sale_list,buy_list]
return trade_price_list
#网格交易入口:
def grid_trade_start(self,symbol):
#进行状态获取,上涨/下跌
# trend_status = self.kline_trend_check(symbol)
#获取可否进行交易
trade_infor = self.make_trade_check(symbol)
#进行判断是否交易,判断是否可以卖出
# if trend_status == 'is_up' and trade_infor['price'] > 0 and trade_infor['trade_type'] == 'sale':
if trade_infor['price'] > 0 and trade_infor['trade_type'] == 'sale':
buy_price = float('%.6f' % (trade_infor['price'] - sale_buy_diff))
#调用下单功能,先调用卖,再调用买
order_id = exchange.Sell(trade_infor['price'], trade_amount)
#Log('order_id:',order_id)
#检查下单是否成功,不成功,则直接返回
if order_id is None:
Log("下单失败,等待600s继续.........")
sleep(600)
return 0
#检查主交易是否成功:判断卖单单是否交易成功,交易成功则进行买单下单
for i in range(100):
sale_orders = exchange.GetOrder(order_id)
#Log('sale_orders:',sale_orders)
if sale_orders.Status == 1:
#如果卖单已成交,则进行买单提交
exchange.Buy(buy_price, trade_amount)
return 0
sleep(10)
#如果循环1000次还未成交,则取消订单
exchange.CancelOrder(order_id)
# 进行判断是否交易,判断是否可以买入
if trade_infor['price'] > 0 and trade_infor['trade_type'] == 'buy':
sale_price = float('%.6f' % (trade_infor['price'] + sale_buy_diff))
# 调用下单功能,先调用买入,再调用卖出
order_id = exchange.Buy(trade_infor['price'], trade_amount)
# 检查下单是否成功,不成功,则直接返回
if order_id is None:
#Log("下单失败,等待600s继续.........")
sleep(600)
return 0
# 检查主交易是否成功:判断买单是否交易成功,交易成功则进行卖单下单
for i in range(100):
buy_orders = exchange.GetOrder(order_id)
if buy_orders.Status == 1:
# 如果买单已成交,则进行卖单提交
exchange.Sell(sale_price, trade_amount)
return 0
sleep(10)
# 如果循环1000次还未成交,则取消订单
exchange.CancelOrder(order_id)
#进行循环调用
def grid_trade_cycle(self,symbol):
cycle_num = 0
while(True):
timestr = (datetime.datetime.now()).strftime('%H%M%S')
self.grid_trade_start(symbol)
sleep(10)
cycle_num = cycle_num + 1
if cycle_num % 100 == 0:
account_infor = exchange.GetAccount()
Log("当前用户的账号信息:%s,....当前已循环检查次数:%s"%(account_infor,str(cycle_num)))
def main():
Log(exchange.GetAccount())
Log("测试")
fmz_market_instances = fmz_market()
fmz_market_instances.grid_trade_cycle(100)
#order_id = exchange.Sell(10000,1)
```
> 策略出处
https://www.fmz.com/strategy/175807
> 更新时间
2019-12-06 14:54:19
+463
View File
@@ -0,0 +1,463 @@
> 策略名称
期货做市高频交易策略
> 策略作者
John
> 策略描述
这个策略属于期货的做市策略
会对盘口价格造成影响
所以不适合大资金.
策略为研究市场行为而写, 实盘请用小资金测试.
> 策略参数
|参数|默认值|描述|
|----|----|----|
|ContractType|0|合约类型: 周|月|季: 周|月|季|
|MLevel|0|杠杆大小: 5倍|10倍|20倍: 5倍|10倍|20倍|
|DepthBuy|5|买单深度|
|DepthSell|5|卖单深度|
|Interval|500|出错重试间隔(毫秒)|
|LoopInterval|2|轮询间隔(秒)|
|SlidePrice|0.01|滑点|
|MinDiff|0.5|盘口最小差价|
|KeepStocksRate|true|保证金保留倍数|
|Lot|80|开仓手数|
|LotCover|200|平仓手数|
|StopLoss|3|最大亏损波动(元)|
|StopProfit|0.5|目标利润点(元)|
|OpType|0|操作类型: 做多|做空|自动: 做多|做空|自动|
|EMA_Fast|7|EMA快线周期|
|EMA_Slow|12|EMA慢线周期|
|EMAInterval|50|EMA检测间隔(秒)|
|WaitType|0|K线收集完成前: 做多|做空|等待: 做多|做空|等待|
|DisableLog|false|关闭订单跟踪|
> 源码 (javascript)
``` javascript
var DO_IDLE = 0;
var DO_LONG = 1;
var DO_SHORT = 2;
var _MarginLevel = [5, 10, 20][MLevel];
var _ContractType = ["week", "month", "quarter"][ContractType];
var _CurrentDirection = [DO_LONG, DO_SHORT, DO_IDLE][OpType != 2 ? OpType : WaitType];
var _isAuto = OpType == 2;
var _IsBitVC = false;
var _Is796 = false;
var _IsOKCoin = false;
var _MinAmount = 0;
var _Fee = 0.0003;
function _N(v, precision) {
if (typeof(precision) != 'number') {
precision = _IsOKCoin ? 3 : 2;
}
var d = parseFloat(v.toFixed(Math.max(10, precision + 5)));
s = d.toString().split(".");
if (s.length < 2 || s[1].length <= precision) {
return d;
}
var b = Math.pow(10, precision);
return Math.floor(d * b) / b;
}
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 GetPosition(orderType) {
var positions;
while (!(positions = exchange.GetPosition())) {
Sleep(Interval);
}
for (var i = 0; i < positions.length; i++) {
if (positions[i].ContractType == _ContractType && positions[i].Type == orderType) {
return positions[i];
}
}
return null;
}
function GetAccount() {
var account;
while (!(account = exchange.GetAccount())) {
Sleep(Interval);
}
return account;
}
function GetLimit() {
var ticker;
while (!(ticker = exchange.GetTicker())) {
Sleep(Interval);
}
if (IsVirtual()) {
return {
high: ticker.Sell + 100,
low: ticker.Buy - 100
};
}
var js = exchange.GetRawJSON();
try {
var obj = JSON.parse(js);
return {
high: parseFloat(obj.limit_highest_price),
low: parseFloat(obj.limit_lowest_price)
};
} catch (e) {
Log(e);
}
return null;
}
function GetDepth() {
var depth;
while (true) {
depth = exchange.GetDepth();
if (depth && depth.Asks.length > 0 && depth.Bids.length > 0 && depth.Asks[0].Price > depth.Bids[0].Price) {
break;
}
Sleep(Interval);
}
return depth;
}
var LastOpenPrice = 0;
var LastCoverPrice = 0;
var LastHoldPrice = 0;
var LastRecord = null;
var LastEMATime = 0;
function GetDirection() {
if (OpType != 2) {
return _CurrentDirection;
}
var n = new Date().getTime();
if ((n - LastEMATime) < (EMAInterval * 1000)) {
return _CurrentDirection;
}
LastEMATime = n;
var records = exchange.GetRecords();
if (!records || records.length < (EMA_Slow + 3)) {
return _CurrentDirection;
}
var newLast = records[records.length - 1];
if ((!LastRecord) || (LastRecord.Time == newLast.Time && LastRecord.Close == newLast.Close)) {
if (!LastRecord) {
LastRecord = newLast;
}
return _CurrentDirection;
}
LastRecord = newLast;
var emaFast = TA.EMA(records, EMA_Fast);
var emaSlow = TA.EMA(records, EMA_Slow);
return emaFast[emaFast.length - 1] >= emaSlow[emaSlow.length - 1] ? DO_LONG : DO_SHORT;
}
function GetPrice() {
var buyPrice = 0;
var buyAmount = 0;
var sellPrice = 0;
var sellAmount = 0;
var depth = GetDepth();
for (var i = 0; i < depth.Asks.length; i++) {
sellAmount += depth.Asks[i].Amount;
if (sellAmount >= DepthSell) {
sellPrice = depth.Asks[i].Price;
break;
}
}
for (var i = 0; i < depth.Bids.length; i++) {
buyAmount += depth.Bids[i].Amount;
if (buyAmount >= DepthBuy) {
buyPrice = depth.Bids[i].Price;
break;
}
}
var diff = MinDiff - (sellPrice - buyPrice);
if (diff >= 0) {
buyPrice = buyPrice - (diff / 2);
sellPrice = sellPrice + (diff / 2);
} else {
buyPrice += SlidePrice;
sellPrice -= SlidePrice;
}
return {
buy: buyPrice,
sell: sellPrice
};
}
function updateProfit() {
var account = GetAccount();
if (_IsBitVC) {
try {
var obj = JSON.parse(exchange.GetRawJSON());
LogProfit(obj.dynamicRights, 'Stocks:', account.Stocks, 'FrozenStocks:', account.FrozenStocks);
} catch (e) {
Log(e);
}
} else {
LogProfit(account.Stocks + account.FrozenStocks);
}
}
var _prePositions = 0;
function onTick() {
var price = GetPrice();
if (_IsBitVC) {
var limit = GetLimit();
if (limit) {
price.sell = Math.max(Math.min(price.sell, limit.high), limit.low);
price.buy = Math.min(Math.max(price.buy, limit.low), limit.high);
}
}
var openFunc = _CurrentDirection == DO_LONG ? exchange.Buy : exchange.Sell;
var openDirection = _CurrentDirection == DO_LONG ? "buy" : "sell";
var openTradeType = _CurrentDirection == DO_LONG ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
var coverFunc = _CurrentDirection == DO_LONG ? exchange.Sell : exchange.Buy;
var coverDirection = _CurrentDirection == DO_LONG ? "closebuy" : "closesell";
var coverTradeType = _CurrentDirection == DO_LONG ? ORDER_TYPE_SELL : ORDER_TYPE_SELL;
var openPrice = _N(_CurrentDirection == DO_LONG ? price.buy : price.sell);
var coverPrice = _N(_CurrentDirection == DO_LONG ? price.sell : price.buy);
var op = 0;
var isFighting = false;
var marketCoverPrice = coverPrice;
if (LastHoldPrice > 0 && LastCoverPrice > 0) {
if (_CurrentDirection == DO_LONG) {
isFighting = (LastHoldPrice - coverPrice) <= StopLoss;
if (isFighting) {
coverPrice = _N((LastHoldPrice * (1 + _Fee)) + StopProfit);
} else {
isFighting = true;
}
} else {
isFighting = (coverPrice - LastHoldPrice) <= StopLoss;
if (isFighting) {
coverPrice = _N((LastHoldPrice * (1 - _Fee)) - StopProfit);
}
}
}
if (LastHoldPrice > 0) {
LogStatus(_CurrentDirection == DO_LONG ? "多仓" : "空仓", isFighting ? "僵持中.." : "止损中..", "持仓均价: ", _N(LastHoldPrice), "盘口平仓价:", marketCoverPrice, isFighting ? "#0000ff" : "#ff0000");
} else {
LogStatus(_CurrentDirection == DO_LONG ? "做多" : "做空", "开仓价: ", openPrice, "平仓价:", marketCoverPrice, "抢盘中... #428bca");
}
if (openPrice != LastOpenPrice) {
op = 1;
}
if (coverPrice != LastCoverPrice) {
op = op == 0 ? 2 : 3;
}
if (op == 3) {
CancelPendingOrders();
} else if (op != 0) {
CancelPendingOrders(op == 1 ? openTradeType : coverTradeType);
} else {
return;
}
var position = 0;
var hold = GetPosition(openTradeType);
if (hold) {
position = hold.Amount;
LastHoldPrice = hold.Price;
} else {
LastHoldPrice = 0;
}
var coverAmount = _N(Math.min(position, _IsBitVC ? (LotCover * 100) : LotCover));
if (!_Is796) {
coverAmount = parseInt(coverAmount);
}
if (_IsBitVC) {
coverAmount = parseInt(parseInt(coverAmount / 100) * 100);
}
if ((op == 2 || op == 3) && (coverAmount >= _MinAmount)) {
exchange.SetDirection(coverDirection);
if (coverFunc(coverPrice, coverAmount, "上次平仓价格", LastCoverPrice) > 0) {
LastCoverPrice = coverPrice;
}
}
if (position == 0 && _prePositions != 0) {
updateProfit();
_prePositions = 0;
}
var d = GetDirection();
if (_prePositions == 0) {
_prePositions = position;
}
if (_isAuto) {
if (d != _CurrentDirection) {
if (position == 0 && GetOrders().length == 0) {
Log(d == DO_LONG ? "开始做多" : "开始做空");
_CurrentDirection = d;
}
return;
}
}
var account = GetAccount();
var canUsedStocks = account.Stocks;
if (KeepStocksRate > 0) {
canUsedStocks = _N(Math.max(account.Stocks - _N((position * (_IsOKCoin ? 10 : 1) / _MarginLevel / (_Is796 ? 1 : openPrice)) * KeepStocksRate), 0) / KeepStocksRate);
}
var openAmount = 0;
if (_IsBitVC) {
openAmount = parseInt(parseInt(Math.min(((canUsedStocks * _MarginLevel * (openPrice * 0.9)) / 100), Lot)) * 100);
} else if (_IsOKCoin) {
openAmount = parseInt(Math.min(((canUsedStocks * _MarginLevel * (openPrice * 0.9)) / 10), Lot));
} else {
openAmount = _N(Math.min(canUsedStocks * _MarginLevel, Lot));
}
if ((op == 1 || op == 3) && (openAmount >= _MinAmount)) {
exchange.SetDirection(openDirection);
if (openFunc(openPrice, openAmount, "上次建仓价格", LastOpenPrice) > 0) {
LastOpenPrice = openPrice;
}
}
}
function onexit() {
CancelPendingOrders();
Log("Exit");
}
function main() {
var eName = exchange.GetName();
if (eName.indexOf("Futures") == -1) {
throw "该策略为期货专用策略";
}
if (_IsOKCoin && _MarginLevel == 5) {
throw "OKCoin期货只支持10倍或20倍杠杆";
}
if (DisableLog) {
EnableLog(false);
}
_IsBitVC = eName.indexOf("BitVC") != -1;
_Is796 = eName.indexOf("796") != -1;
_IsOKCoin = eName.indexOf("OKCoin") != -1;
if (_IsBitVC) {
_MinAmount = 100;
} else if (_IsOKCoin) {
_MinAmount = 1;
} else {
_MinAmount = exchange.GetMinStock();
}
exchange.SetRate(1);
Log(exchange.GetName(), GetAccount());
CancelPendingOrders();
LoopInterval = Math.max(LoopInterval, 1);
EMAInterval = Math.max(EMAInterval, 1);
if (_IsBitVC || _IsOKCoin) {
Lot = parseInt(Math.max(1, Lot));
LotCover = parseInt(Math.max(1, LotCover));
if (Lot < 1 || LotCover < 1) {
throw "手数最少为1, BitVC一手相当于100元人民币, OKCoin相当于10美金.";
}
}
KeepStocksRate = parseInt(KeepStocksRate);
Log("预留", KeepStocksRate, "倍的保证金");
if (_IsOKCoin && ContractType == 0) {
_ContractType = "this_week";
}
if (!_IsOKCoin && ContractType == 1) {
throw "只有OKCoin期货支持月全约";
}
if (_Is796 && ContractType != 0) {
throw "796只支持周合约类型";
}
exchange.SetContractType(_ContractType);
exchange.SetMarginLevel(_MarginLevel);
if (OpType == 2) {
Log("开始收集K线信息, 请耐心等待.");
}
while (true) {
if (_CurrentDirection == DO_IDLE) {
_CurrentDirection = GetDirection();
} else {
onTick();
}
Sleep(LoopInterval * 1000);
}
}
```
> 策略出处
https://www.fmz.com/strategy/194180
> 更新时间
2020-04-15 14:13:39
-76
View File
@@ -1,76 +0,0 @@
> 策略名称
期货看穿式测试
> 策略作者
Hukybo
> 源码 (javascript)
``` javascript
num = 0
function onTick() {
if (num < 1) {
_C(exchange.SetContractType, "rb2001")
account = _C(exchange.GetAccount).Info.AccountID
Log("账号:", account);
Log("AppID:", "client_fmz_1.0");
records = _C(exchange.GetRecords)
k = records[records.length - 1].Close
exchange.SetDirection("buy");
id = exchange.Buy(k + 2, 1)
Log("sessionid:", id);
Log("登陆时间:", Date());
Log("账号:", account);
records = _C(exchange.GetRecords)
k = records[records.length - 1].Close
for (x = 0; x < 5; x++) {
exchange.SetDirection("buy");
id = exchange.Buy(k + 2, 1)
Log("sessionid:", id);
Sleep(1000)
}
Log("账号:", account);
for (y = 0; y < 5; y++) {
exchange.SetDirection("buy");
id = exchange.Buy(k - 2, 1)
Log("sessionid:", id);
Sleep(1000)
}
orders = _C(exchange.GetOrders)
for (z = 0; z < 5; z++) {
Log("账号:", account);
Log("合约:", "rb1910");
var ordersid = orders[z].Id
if (exchange.CancelOrder(ordersid)) {
Log("订单:" + ordersid + " 已撤单")
}
}
num++
}
}
function main() {
while (true) {
onTick();
Sleep(1000);
}
}
```
> 策略出处
https://www.fmz.com/strategy/152670
> 更新时间
2019-09-09 16:12:19
+3 -2
View File
@@ -9,7 +9,8 @@ Zero
> 策略描述
BotVS支持策略同时展现多个图表, 这是一个简单的例子. 如果不能正常展示, 请清空浏览器缓存后刷新
平台支持策略同时展现多个图表, 这是一个简单的例子
具体使用方法可参考API文档中的Chart部分 https://www.fmz.com/api#chart
@@ -156,4 +157,4 @@ https://www.fmz.com/strategy/38203
> 更新时间
2019-01-24 17:33:12
2020-04-08 14:53:51
@@ -0,0 +1,72 @@
> 策略名称
测试现货买卖操作(分限价、市价两种情况)
> 策略作者
himandy
> 策略描述
回测火币数据,以及在wexapp模拟盘交易,都得到类似下面的运行结果:
如果限价下单,那么exchange.Buy(6840, 5)就是以6840的价格买入5个btc。
如果市价下单,那么exchange.Buy(-1, 5)就是以市价、花费5个usdt买入btc。
策略代码:https://www.fmz.com/m/edit-strategy/191349
2020年4月5日
> 源码 (javascript)
``` javascript
/*backtest
start: 2020-01-01 00:00:00
end: 2020-04-01 00:00:00
period: 1d
exchanges: [{"eid":"Huobi","currency":"BTC_USD","balance":1000000,"stocks":0}]
*/
var id, order, buyAmount, lastPrice;
function main() {
Log(exchange.GetAccount());
lastPrice = parseInt(exchange.GetTicker().Last);
id = exchange.Buy(lastPrice + 50, 5); // 限价买入5个BTC,买入价是当前最新价格+50
Log(order = exchange.GetOrder(id));
buyAmount = parseFloat(order.DealAmount);
Log(exchange.GetAccount());
Sleep(1000);
last_price = parseInt(exchange.GetTicker().Last);
id = exchange.Sell(lastPrice - 50, buyAmount); // 限价卖出5个BTC,卖出价是当前最新价格-50
Log(order = exchange.GetOrder(id));
Log(exchange.GetAccount());
Sleep(1000);
id = exchange.Buy(-1, 5); // 市价买入BTC,成交量是5个usdt
Sleep(1000);
Log(order = exchange.GetOrder(id));
buyAmount = parseFloat(order.DealAmount);
Log(exchange.GetAccount());
Sleep(1000);
id = exchange.Sell(-1, buyAmount); // 市价卖出BTC,成交量是刚才买入的BTC
Sleep(1000);
Log(order = exchange.GetOrder(id));
Log(exchange.GetAccount());
}
```
> 策略出处
https://www.fmz.com/strategy/191349
> 更新时间
2020-04-06 12:15:13
+159
View File
@@ -0,0 +1,159 @@
> 策略名称
混合图表的一个复杂例子
> 策略作者
Zero
> 策略描述
更多需求请直接查询 [Highchart官方](https://www.highcharts.com/) 或 [Highchart第三方中文文档](https://www.highcharts.com.cn/)
![IMG](https://www.fmz.com/upload/asset/15adb3835db63ae637d.png)
> 源码 (javascript)
``` javascript
/*backtest
start: 2020-03-11 00:00:00
end: 2020-04-09 23:59:00
period: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/
var chartCfg = {
subtitle: {
text: "subtitle",
},
yAxis: [{
height: "40%",
lineWidth: 2,
title: {
text: 'PnL',
},
tickPixelInterval: 20,
minorGridLineWidth: 1,
minorTickWidth: 0,
opposite: true,
labels: {
align: "right",
x: -3,
}
}, {
title: {
text: 'Profit',
},
top: "42%",
height: "18%",
offset: 0,
lineWidth: 2
}, {
title: {
text: 'Vol',
},
top: '62%',
height: '18%',
offset: 0,
lineWidth: 2
}, {
title: {
text: 'Asset',
},
top: '82%',
height: '18%',
offset: 0,
lineWidth: 2
}],
series: [{
name: 'PnL',
data: [],
id: 'primary',
tooltip: {
xDateFormat: '%Y-%m-%d %H:%M:%S'
},
yAxis: 0
}, {
type: 'column',
lineWidth: 2,
name: 'Profit',
data: [],
yAxis: 1,
}, {
type: 'column',
name: 'Trade',
data: [],
yAxis: 2
}, {
type: 'area',
step: true,
lineWidth: 0,
name: 'Long',
data: [],
yAxis: 2
}, {
type: 'area',
step: true,
lineWidth: 0,
name: 'Short',
data: [],
yAxis: 2
}, {
type: 'line',
step: true,
color: '#5b4b00',
name: 'Asset',
data: [],
yAxis: 3
}, {
type: 'pie',
innerSize: '70%',
name: 'Random',
data: [],
center: ['3%', '6%'],
size: '15%',
dataLabels: {
enabled: false
},
startAngle: -90,
endAngle: 90,
}],
};
function main() {
let c = Chart(chartCfg);
let preTicker = null;
while (true) {
let t = exchange.GetTicker();
c.add(0, [t.Time, t.Last]); // PnL
c.add(1, [t.Time, preTicker ? t.Last - preTicker.Last : 0]); // profit
let r = Math.random();
var pos = parseInt(t.Time/86400);
c.add(2, [t.Time, pos/2]); // Vol
c.add(3, [t.Time, r > 0.8 ? pos : null]); // Long
c.add(4, [t.Time, r < 0.8 ? -pos : null]); // Short
c.add(5, [t.Time, Math.random() * 100]); // Asset
// update pie
chartCfg.series[chartCfg.series.length-1].data = [
["A", Math.random()*100],
["B", Math.random()*100],
];
c.update(chartCfg)
preTicker = t;
}
}
```
> 策略出处
https://www.fmz.com/strategy/196963
> 更新时间
2020-04-11 12:57:17
@@ -0,0 +1,90 @@
> 策略名称
用FMZ的均线的交易方式PYTHON版本2
> 策略作者
a838899
> 源码 (python)
``` python
'''
用FMZ的均线的交易方式PYTHON版本
交易对象时OKEX BTC_USDT
方法:
用公式计算的MA曲线数据、 用的FMZ的TA库
用1小时的线周期,MA5上穿MA20 买入 MA5下穿MA20 卖出
欢迎学习交流
微信:su7178
欢迎学习交流
'''
'''backtest
start: 2020-03-13 00:00:00
end: 2020-04-13 00:00:00
period: 1h
exchanges: [{"eid":"OKEX","currency":"BTC_USD"}]
'''
buy_m = 0
sell_m = 0
def do_trade(trade_type):
nw_accont = _C(exchange.GetAccount)
money = nw_accont.Balance
B = nw_accont.Stocks
if trade_type == "buy" and money >= 10:
exchange.Buy(-1, money)
global buy_m
buy_m += 1
Log("买入btc资金 : ", money,"买入btc数量 : ", B,"买入次数 : ",buy_m)
elif trade_type == "sell" and B >= 0.001:
exchange.Sell(-1, B)
global sell_m
sell_m += 1
Log("卖出btc资金 : ", money,"卖出btc数量 : ", B,"卖出次数 : ",sell_m)
else: return
# 策略主函数
def onTick():
# exchange.SetContractType("quarter") # 订阅期货品种
records = exchange.GetRecords(PERIOD_H1) # 获取K线数组
# records_15 = records.
if len(records) < 50: return
close = records[len(records) - 1].Close
ma_5 = TA.MA(records, 5)
# Log(ma_5)
ma_20 = TA.MA(records, 20)
cross = 0
cross = _Cross(ma_5, ma_20)
if cross == -1:
trade_type = "buy"
do_trade(trade_type)
elif cross == 1:
trade_type = "sell"
do_trade(trade_type)
else: return
# 程序入口
def main():
accont = _C(exchange.GetAccount)
int_money = accont.Balance
Log("初始资金 : ", int_money)
int_B = accont.Stocks
Log("初始BTC : ", int_B)
while True: # 进入无限循环模式
onTick() # 执行策略主函数
Sleep(3000) # 休眠1秒
```
> 策略出处
https://www.fmz.com/strategy/198397
> 更新时间
2020-04-14 14:56:42
@@ -0,0 +1,55 @@
> 策略名称
简单的股票趋势跟踪交易策略
> 策略作者
Zero
> 策略描述
> 说明
现阶段股票只支持回测, 选股功能下一步将加入,最后再进行实盘支持
> 源码 (麦语言)
``` pascal
(*backtest
start: 2016-03-01 09:00:00
end: 2020-03-01 15:00:00
period: 1d
exchanges: [{"eid":"Futures_LTS","currency":"STOCK","minFee":0}]
args: [["TradeAmount",100,126961],["ContractType","601398.SH",126961]]
*)
M := 12; // 参数范围 1, 20
N := 3; // 参数范围 1, 10
SDEV := 2; // 参数范围 1, 10
P := 16; // 参数范围 1, 20
//该策略为趋势跟踪交易策略,适用较大周期,如日线。
//该模型仅用作模型开发案例,依此入市,风险自负。
////////////////////////////////////////////////////////
//平移BOLL通道计算
MID:=MA(C,N);//计算中轨
TMP:=STD(C,M)*SDEV;//计算标准差
DISPTOP:=REF(MID,P)+TMP;//平移BOLL通道上轨
DISPBOTTOM:=REF(MID,P)-TMP;//平移BOLL通道下轨
//系统入场
H>=DISPTOP,BPK;
L<=DISPBOTTOM,SPK;
AUTOFILTER;
```
> 策略出处
https://www.fmz.com/strategy/195935
> 更新时间
2020-04-08 13:41:15
@@ -1,66 +0,0 @@
> 策略名称
简单预定买入后卖出机器人|Buy then Sell (ping-pong strategy)
> 策略作者
小草
> 策略描述
如题,可设定买入价格,买入成功后自动挂卖出价格卖出,
> 策略参数
|参数|默认值|描述|
|----|----|----|
|BUYPRICE|6200|buy price|
|BUYAMOUNT|0.1|buy amount|
|SELLPRICE|6400|sell price after buying|
|Intervel|6|sleep time (second)|
> 源码 (javascript)
``` javascript
function CancelPendingOrders() {
var orders = _C(exchange.GetOrders);
for (var j = 0; j < orders.length; j++) {
exchange.CancelOrder(orders[j].Id, orders[j]);
}
}
function main() {
Log('robot starts to run')
if(BUYPRICE >= SELLPRICE){
throw 'check buy and sell price'
}
CancelPendingOrders()
var account = _C(exchange.GetAccount)
var init_account = account
Log('account: ', account.Balance);
if(account.Balance > BUYPRICE*BUYAMOUNT){
exchange.Buy(BUYPRICE, BUYAMOUNT);
}else{
throw 'account balances is not enough'
}
while(true){
account = _C(exchange.GetAccount)
if(account.Stocks >= init_account.Stocks + 0.01){
exchange.Sell(SELLPRICE, account.Stocks - init_account.Stocks)
}
Sleep(Intervel*1000)
}
}
```
> 策略出处
https://www.fmz.com/strategy/121228
> 更新时间
2019-10-22 14:57:26
@@ -411,7 +411,7 @@ function fishing(orgAccount, fishCount) {
exchange.SetDirection(BuyFirst ? "closebuy" : "closesell");
}
var coverId = CoverFunc(coverPrice, BuyFirst ? amountS : amountB, BuyFirst ? '完成买单:' : '完成卖单:', openPrice);
if (coverId > 0) {
if (coverId) {
fishTable[idx] = STATE_WAIT_CLOSE;
uuidTable[idx] = coverId;
}
@@ -420,7 +420,7 @@ function fishing(orgAccount, fishCount) {
exchange.SetDirection(BuyFirst ? "buy" : "sell");
}
var openId = OpenFunc(openPrice, BuyFirst ? amountB : amountS);
if (openId > 0) {
if (openId) {
fishTable[idx] = STATE_WAIT_COVER;
uuidTable[idx] = openId;
if (state == STATE_WAIT_CLOSE) {
@@ -496,4 +496,4 @@ https://www.fmz.com/strategy/8474
> 更新时间
2018-06-05 15:09:40
2020-04-06 18:47:43
-70
View File
@@ -1,70 +0,0 @@
> 策略名称
获取最新疫情|Fetch nCoV News
> 策略作者
fmzero
> 策略描述
病毒无情,人间有爱。
FMZ一直有情怀。
丁香园一直做实时发布疫情发展情况,而我想通过FMZ的`HttpQuery`爬取其实时信息。并用Log(...&)推送至微信公众号上,用LogStatus展现信息(有人说可能没卵用)。
这就是温度。
如下代码未能实现正则表达式过滤信息,仅仅是一个半成品。望大神助力
[温度](https://www.fmz.com/strategy/182505)
> 源码 (javascript)
``` javascript
// 有温度的FMZ
var url = 'https://3g.dxy.cn/newh5/view/pneumonia'
var newsRegex = "/<script id=\"getTimelineService\">.+?window.getTimelineService\s=\s({.+?)}catch\(e\){}<\/script>/im"
var provinceRegex = "/<script id=\"getListByCountryTypeService1\">.+?window.getListByCountryTypeService1\s=\s(\[.+?])}catch\(e\){}<\/script>/im"
///////////////////////////////////////////
function get_dxy_data() {
var ret = HttpQuery(url)
return ret
}
function get_nCoV_news(content ) {
var news = content.match(newsRegex)
Log(news)
}
function get_nCoV_province(content) {
var ret = HttpQuery(url)
var province = ret.search(provinceRegex)
Log(province)
}
function main() {
while(true) {
Sleep(10 * 1000)
var content = get_dxy_data()
if(content === null) {
continue
}
get_nCoV_news(content)
get_nCoV_province(content)
}
}
```
> 策略出处
https://www.fmz.com/strategy/182505
> 更新时间
2020-01-24 14:23:36
@@ -1,348 +0,0 @@
> 策略名称
通用协议(Python3.X版)——改编自CoinPark交易所通用协议 6.27 16:00 更新 关闭了SSL验证
> 策略作者
orienter
> 策略描述
## CoinPark通用协议Python2版本
用途:可以使BotVs支持coinpark.cc交易所
代码公开地址:https://www.fmz.com/strategy/101399
运行地址
http://127.0.0.1:6667
### 1.在托管者所在服务器运行插件
在保存成文件上传的托管者所在服务器,后台运行即可:
nohup python coinpark.py &
也可以在运行时指定端口:
python coinpark.py 8866
也可以当成一个普通机器人运行在模拟盘上,不收取费用。
### 2.在FMZ网站配置交易所
交易所配置如下:
![iamge](https://dn-filebox.qbox.me/c1456599386e597f2966f67b49c7102bab857fef.png)
由于账户没资产,未作详细测试,欢迎反馈Bug
2018.6.26 15:57 更新,修改了Bug
> 源码 (python)
``` python
# -*- coding: utf-8 -*-
'''
CoinPark通用协议,使用Python3.7
运行地址:http://127.0.0.1:6667,端口可指定
由于账户没资产,未作详细测试,欢迎反馈Bug
QQ:124404425
可以把通用协议当成普通机器人,运行在BotVs模拟盘即可,不收取费用
为了使用IO函数,需要重载exchange里的rpc方法,js的例子如下:
exchange.rpc = function(path, obj) {
return exchange.IO("api","POST", path, "obj="+escape(JSON.stringify(obj)));
}
function main() {
Log(exchange.rpc("/transfer", {cmd: "transfer/assets", body: {select:1}}));
}
'''
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
import urllib
import urllib.request as urllib2
import time
import hmac
import hashlib
import random
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
def httpGet(url):
headers = {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
req = urllib2.Request(url,headers=headers)
response = urllib2.urlopen(req)
return json.loads(response.read())
def getsign(data,secret):
result = hmac.new(secret.encode("utf-8"), data.encode("utf-8"), hashlib.md5).hexdigest()
return result
def httpPostWithSign(url, cmds, api_key, api_secret):
headers = {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
s_cmds = json.dumps(cmds)
sign = getsign(s_cmds,api_secret)
req = urllib2.Request(url, urllib.urlencode({'cmds': s_cmds, 'apikey': api_key,'sign':sign}), headers=headers)
response = urllib2.urlopen(req)
return json.loads(response.read())
class MyExchange:
market_url = "https://api.coinpark.cc/v1/mdata"
trade_url = "https://api.coinpark.cc/v1"
kline_period = {1:'1min', 3:'3min', 5:'5min', 15:'15min', 30:'30min',\
60:'1hour', 120:'2hour', 240:'4hour', 360:'6hour', \
60*12:'12hour', 60*24:'day', 60*24*7:'week'}
@staticmethod
def GetTicker(symbol):
url = MyExchange.market_url + "?cmd=ticker&pair=" + symbol
raw_data = httpGet(url)
if 'error' in raw_data.keys():
return {'error':json.dumps(raw_data['error'],encoding="utf8", ensure_ascii=False)}
ret_data = {"data": {"time": raw_data['result']['timestamp'], "buy": raw_data['result']['buy'],\
"sell": raw_data['result']['sell'], "last": raw_data['result']['last'],\
"high": raw_data['result']['high'], "low": raw_data['result']['low'],\
"vol": raw_data['result']['vol']}}
return ret_data
@staticmethod
def GetDepth(symbol):
url = MyExchange.market_url + "?cmd=depth&size=10&pair=" + symbol
raw_data = httpGet(url)
if 'error' in raw_data.keys():
return {'error':json.dumps(raw_data['error'],encoding="utf8", ensure_ascii=False)}
ret_data = {"data" : {"time" : raw_data['result']['update_time'], "asks" : [], "bids" : []}}
for bid in raw_data['result']['bids']:
ret_data['data']['bids'].append([bid['price'],bid['volume']])
for ask in raw_data['result']['asks']:
ret_data['data']['asks'].append([ask['price'],ask['volume']])
return ret_data
@staticmethod
def GetRecords(symbol, period):
url = MyExchange.market_url + "?cmd=kline&size=200&period=%s&pair="%MyExchange.kline_period[period] + symbol
raw_data = httpGet(url)
if 'error' in raw_data.keys():
return {'error':json.dumps(raw_data['error'],encoding="utf8", ensure_ascii=False)}
ret_data = {"data": []}
for kline in raw_data['result']:
ret_data['data'].append([kline['time'], kline['open'], kline['high'],\
kline['low'], kline['close'], kline['vol']])
return ret_data
@staticmethod
def GetTrades(symbol):
url = MyExchange.market_url + "?cmd=deals&size=50&pair=" + symbol
raw_data = httpGet(url)
if 'error' in raw_data.keys():
return {'error':json.dumps(raw_data['error'],encoding="utf8", ensure_ascii=False)}
ret_data = {"data":[]}
for trade in raw_data["result"]:
ret_data["data"].append({"id":trade["id"], "time":trade["time"], \
"price":trade["price"], "amount":trade["amount"],"type":"buy" if int(trade["side"])==1 else "sell"})
return ret_data
@staticmethod
def GetAccount(api_key, api_secret):
url = MyExchange.trade_url + "/transfer"
cmds = [{"cmd": "transfer/assets", "body": {"select":1}}]
raw_data = httpPostWithSign(url, cmds, api_key, api_secret)
if 'error' in raw_data.keys():
return {'error':json.dumps(raw_data['error'],encoding="utf8", ensure_ascii=False)}
ret_data = {"data": []}
if "assets_list" in raw_data["result"][0]["result"].keys():
for asset in raw_data["result"][0]["result"]["assets_list"]:
ret_data["data"].append({"currency":asset["coin_symbol"], \
"free":asset["balance"], "frozen":asset["freeze"]})
ret_data["raw"] = raw_data["result"]
return ret_data
@staticmethod
def Trade(api_key, api_secret, pair, order_type, order_side, price, amount):
url = MyExchange.trade_url + "/orderpending"
cmds = [{
'cmd':"orderpending/trade",
'index': random.randint(0,2000),
'body':{
'pair':pair,
'account_type':0,
'order_type':order_type,
'order_side':order_side,
'price':price,
'amount':amount,
}
}]
if order_type==1:
cmds['money'] = amount
raw_data = httpPostWithSign(url, cmds, api_key, api_secret)
if 'error' in raw_data.keys():
return {'error':json.dumps(raw_data['error'],encoding="utf8", ensure_ascii=False)}
ret_data = {"data": {'id':raw_data['result'][0]['result']}}
return ret_data
@staticmethod
def CancelOrder(api_key, api_secret, orders_id):
url = MyExchange.trade_url + "/orderpending"
cmds = [{
'cmd':"orderpending/cancelTrade",
'index': random.randint(0,2000),
'body':{'orders_id':orders_id}
}]
raw_data = httpPostWithSign(url, cmds, api_key, api_secret)
if 'error' in raw_data.keys():
return {'error':json.dumps(raw_data['error'],encoding="utf8", ensure_ascii=False)}
ret_data = {"data":True}
try:
result = raw_data['result'].encode('utf8')
except:
ret_data = {"data":False}
ret_data['raw'] = raw_data
return ret_data
@staticmethod
def GetOrder(api_key, api_secret, orders_id):
url = MyExchange.trade_url + "/orderpending"
cmds = [{
'cmd':"orderpending/order",
'index': random.randint(0,2000),
'body':{'id':orders_id}
}]
raw_data = httpPostWithSign(url, cmds, api_key, api_secret)
if 'error' in raw_data.keys():
return {'error':json.dumps(raw_data['error'],encoding="utf8", ensure_ascii=False)}
status = 'open'
if not raw_data['result'][0]['result']:
return {"error":'Id not found'}
if int(raw_data['result'][0]['result']['status'])==3:
status = 'closed'
if int(raw_data['result'][0]['result']['status'])==5:
status = 'canceled'
ret_data = {
"data": {
"id": raw_data['result'][0]['result']['id'],
"amount": raw_data['result'][0]['result']['amount'],
"price": raw_data['result'][0]['result']['price'],
"status": status,
"deal_amount": raw_data['result'][0]['result']['deal_amount'],
"type": "buy" if raw_data['result'][0]['result']['order_side']==1 else "sell",
"avg_price": 0,
}
}
ret_data['raw'] = raw_data
return ret_data
@staticmethod
def GetOrders(api_key, api_secret, pair):
url = MyExchange.trade_url + "/orderpending"
cmds = [{
'cmd':"orderpending/orderPendingList",
'body':{
'pair':pair,
'page':1,
'size':50
}
}]
raw_data = httpPostWithSign(url, cmds, api_key, api_secret)
if 'error' in raw_data.keys():
return {'error':json.dumps(raw_data['error'],encoding="utf8", ensure_ascii=False)}
ret_data = {"data":[]}
for order in raw_data["result"][0]["result"]["items"]:
status = 'open'
if int(order['status'])==3:
status = 'closed'
if int(order['status'])==5:
status = 'canceled'
ret_data["data"].append(
{
"id": order['id'],
"amount": order['amount'],
"price": order['price'],
"status": status,
"deal_amount": order['deal_amount'],
"type": "buy" if order['order_side']==1 else "sell",
}
)
ret_data['raw'] = raw_data
return ret_data
@staticmethod
def IO(api_key, api_secret, path, params):
url = MyExchange.trade_url + path
cmds = [json.loads(str(urllib.unquote(params['obj'])))]
raw_data = httpPostWithSign(url, cmds, api_key, api_secret)
if 'error' in raw_data.keys():
return {'error':json.dumps(raw_data['error'],encoding="utf8", ensure_ascii=False)}
return {"data":raw_data}
class Server(BaseHTTPRequestHandler):
def do_HEAD(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
def do_POST(self):
self.data_string = self.rfile.read(int(self.headers['Content-Length'])).decode()
data =json.loads(self.data_string.replace("'", '"'))
sent_data = {}
if data['method'] == "ticker":
symbol = data['params']['symbol'].upper()
sent_data = MyExchange.GetTicker(symbol)
elif data['method'] == "depth":
symbol = data['params']['symbol'].upper()
sent_data = MyExchange.GetDepth(symbol)
elif data['method'] == "records":
symbol = data['params']['symbol'].upper()
period = data['params']['period']
sent_data = MyExchange.GetRecords(symbol, int(period))
elif data['method'] == "trades":
symbol = data['params']['symbol'].upper()
sent_data = MyExchange.GetTrades(symbol)
elif data['method'] == "accounts":
access_key = data["access_key"]
secret_key = data["secret_key"]
sent_data = MyExchange.GetAccount(access_key, secret_key)
elif data['method'] == "trade":
access_key = data["access_key"]
secret_key = data["secret_key"]
pair = data['params']['symbol'].upper()
order_side = 1 if data['params']['type'] == 'buy' else 2
price = data['params']['price']
order_type = 2 if price > 0 else 1
amount = data['params']['amount']
sent_data = MyExchange.Trade(access_key, secret_key, pair, order_type, order_side, price, amount)
elif data['method'] == "cancel":
access_key = data["access_key"]
secret_key = data["secret_key"]
orders_id = int(data['params']['id'])
sent_data = MyExchange.CancelOrder(access_key, secret_key, orders_id)
elif data['method'] == "order":
access_key = data["access_key"]
secret_key = data["secret_key"]
orders_id = int(data['params']['id'])
sent_data = MyExchange.GetOrder(access_key, secret_key, orders_id)
elif data['method'] == "orders":
access_key = data["access_key"]
secret_key = data["secret_key"]
pair = data['params']['symbol'].upper()
sent_data = MyExchange.GetOrders(access_key, secret_key, pair)
elif data['method'][:2] == "__":
access_key = data["access_key"]
secret_key = data["secret_key"]
path = data["method"].split('_')[-1]
params = data["params"]
sent_data = MyExchange.IO(access_key, secret_key, path, params)
self.do_HEAD()
self.wfile.write(json.dumps(sent_data).encode())
def run(server_class=HTTPServer, handler_class=Server, port=6667):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
print('Starting http server...')
httpd.serve_forever()
if __name__ == "__main__":
from sys import argv
if len(argv) == 2:
run(port=int(argv[1]))
else:
run()
```
> 策略出处
https://www.fmz.com/strategy/188813
> 更新时间
2020-03-06 20:11:54
+3 -4
View File
@@ -11,9 +11,8 @@ Zero
> 尝个鲜
* 完全兼容文华麦语言语法
* 基于发明者强大的低层, 完全支持数字货币现货期货与国内大宗商品期货
* 兼容工作会一直持续, 目前兼容度90%大部分策略可以直接运行, 无需修改
* 自动移仓换月, 真实反映主力合约切换过程
* API文档 https://www.fmz.com/bbs-topic/2569
>语言增强
@@ -32,7 +31,7 @@ scope.TEST = function(obj) {
上一个收盘价放大100倍:TEST(REF(C, 1)); // 鼠标移动到回测的K线上就会提示变量值
```
![IMG](https://www.fmz.com/upload/asset/81cecb83b47ecca04ddd63c3206eb0db.png)
![IMG](https://www.fmz.com/upload/asset/10739ec1da850b74dcc.png)
> 策略参数
@@ -93,4 +92,4 @@ https://www.fmz.com/strategy/126968
> 更新时间
2018-12-24 13:35:31
2020-04-10 11:40:47