Name
期货做市高频交易策略
Author
John。
Strategy Description
这个策略属于期货的做市策略 会对盘口价格造成影响 所以不适合大资金. 策略为研究市场行为而写, 实盘请用小资金测试.
Strategy Arguments
Argument | Default | Description |
---|---|---|
ContractType | 0 | 合约类型: 周 |
MLevel | 0 | 杠杆大小: 5倍 |
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 | 关闭订单跟踪 |
Source (javascript)
var DO_IDLE = 0;
var DO_LONG = 1;
var DO_SHORT = 2;
var _MarginLevel = [5, 10, 20, 100][MLevel];
var _ContractType = ["week", "month", "quarter", "XBTUSD"][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);
}
}
Detail
https://www.fmz.com/strategy/194180
Last Modified
2020-05-08 00:02:38