지난 기사에서는 간단한 현금 계산 로봇을 구현했고, 오늘 우리는 계약 버전의 간편한 계산 로봇을 구현했습니다.
계약 버전의 일정은 로봇 버전과 현금 버전의 차이점이 크다. 현금 버전은 주로 계정 자산 변화를 모니터링함으로써 달성 할 수 있습니다. 선물 버전은 계정 보유 변동 상황을 모니터링해야합니다. 그래서 선물판의 상황은 좀 더 복잡합니다. 왜냐하면 선물에는 여러 가지 보유가 있고, 빈 보유가 있고, 다른 계약이 있기 때문입니다. 이 일련의 세부 사항을 처리해야 합니다. 핵심 아이디어는 보유 변동량을 모니터링하는 것입니다. 포지션의 변동량에 따라 단일 동작을 촉발한다. 원래는 다중, 빈 헤드를 함께 처리할 계획이었으나, 그렇게 처리하는 것이 복잡해질 수 있다는 것을 알게 되었다. 분석 문제 이후 포지션의 다중, 빈 헤드를 분리 처리하기로 결정되었다.
전략 파라미터:
재검토를 지원하고, 기본 설정으로 바로 재검토 관찰을 설정할 수 있다.
이 전략의 소스 코드는:
/*backtest
start: 2021-03-18 00:00:00
end: 2021-04-07 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD"},{"eid":"Futures_OKCoin","currency":"BTC_USD"},{"eid":"Futures_OKCoin","currency":"BTC_USD"}]
*/
function test() {
// 测试函数
var ts = new Date().getTime()
if (ts % (1000 * 60 * 60 * 6) > 1000 * 60 * 60 * 5.5) {
Sleep(1000 * 60 * 10)
var nowPosAmount = getPosAmount(_C(exchange.GetPosition), refCt)
var longPosAmount = nowPosAmount.long
var shortPosAmount = nowPosAmount.short
var x = Math.random()
if (x > 0.7) {
exchange.SetDirection("buy")
exchange.Buy(-1, _N(Math.max(1, x * 10), 0), "参考账户测试开单#FF0000")
} else if(x < 0.2) {
exchange.SetDirection("sell")
exchange.Sell(-1, _N(Math.max(1, x * 10), 0), "参考账户测试开单#FF0000")
} else if(x >= 0.2 && x <= 0.5 && longPosAmount > 4) {
exchange.SetDirection("closebuy")
exchange.Sell(-1, longPosAmount, "参考账户测试平仓#FF0000")
} else if(shortPosAmount > 4) {
exchange.SetDirection("closesell")
exchange.Buy(-1, _N(shortPosAmount / 2, 0), "参考账户测试平仓#FF0000")
}
}
}
function getPosAmount(pos, ct) {
var longPosAmount = 0
var shortPosAmount = 0
_.each(pos, function(ele) {
if (ele.ContractType == ct && ele.Type == PD_LONG) {
longPosAmount = ele.Amount
} else if (ele.ContractType == ct && ele.Type == PD_SHORT) {
shortPosAmount = ele.Amount
}
})
return {long: longPosAmount, short: shortPosAmount}
}
function trade(e, ct, type, delta) {
var nowPosAmount = getPosAmount(_C(e.GetPosition), ct)
var nowAmount = type == PD_LONG ? nowPosAmount.long : nowPosAmount.short
if (delta > 0) {
// 开仓
var tradeFunc = type == PD_LONG ? e.Buy : e.Sell
e.SetDirection(type == PD_LONG ? "buy" : "sell")
tradeFunc(-1, delta)
} else if (delta < 0) {
// 平仓
var tradeFunc = type == PD_LONG ? e.Sell : e.Buy
e.SetDirection(type == PD_LONG ? "closebuy" : "closesell")
if (nowAmount <= 0) {
Log("未检测到持仓")
return
}
tradeFunc(-1, Math.min(nowAmount, Math.abs(delta)))
} else {
throw "错误"
}
}
function main() {
LogReset(1)
if (exchanges.length < 2) {
throw "没有跟单的交易所"
}
var exName = exchange.GetName()
// 检测参考交易所
if (!exName.includes("Futures_")) {
throw "仅支持期货跟单"
}
Log("开始监控", exName, "交易所", "#FF0000")
// 检测跟单交易所
for (var i = 1 ; i < exchanges.length ; i++) {
if (exchanges[i].GetName() != exName) {
throw "跟单的期货交易所和参考交易所不同!"
}
}
// 设置交易对、合约
_.each(exchanges, function(e) {
if (!IsVirtual()) {
e.SetCurrency(refCurrency)
if (isSimulate) {
if (e.GetName() == "Futures_OKCoin") {
e.IO("simulate", true)
}
}
}
e.SetContractType(refCt)
})
var initRefPosAmount = getPosAmount(_C(exchange.GetPosition), refCt)
while(true) {
if (IsVirtual()) { // 回测时才模拟
test() // 测试函数,模拟参考账户主动交易,触发跟单账户跟单
}
Sleep(5000)
var nowRefPosAmount = getPosAmount(_C(exchange.GetPosition), refCt)
var tbl = {
type : "table",
title : "持仓",
cols : ["名称", "标签", "多仓", "空仓", "账户资产(Stocks)", "账户资产(Balance)"],
rows : []
}
_.each(exchanges, function(e) {
var pos = getPosAmount(_C(e.GetPosition), refCt)
var acc = _C(e.GetAccount)
tbl.rows.push([e.GetName(), e.GetLabel(), pos.long, pos.short, acc.Stocks, acc.Balance])
})
LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`")
// 计算仓位变动量
var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short
// 检测变动
if (longPosDelta == 0 && shortPosDelta == 0) {
continue
} else {
// 检测到仓位变动
for (var i = 1 ; i < exchanges.length ; i++) {
// 执行多头动作
if (longPosDelta != 0) {
Log(exchanges[i].GetName(), exchanges[i].GetLabel(), "执行多头跟单,变动量:", longPosDelta)
trade(exchanges[i], refCt, PD_LONG, longPosDelta)
}
// 执行空头动作
if (shortPosDelta != 0) {
Log(exchanges[i].GetName(), exchanges[i].GetLabel(), "执行空头跟单,变动量:", shortPosDelta)
trade(exchanges[i], refCt, PD_SHORT, shortPosDelta)
}
}
}
// 执行跟单操作后,更新
initRefPosAmount = nowRefPosAmount
}
}
OKEX가 V5 인터페이스를 갱신한 후 OKEX의 모형 디스크를 사용할 수 있기 때문에, 나는 두 개의 OKEX의 모형 디스크 API KEY를 사용하여 매우 편리하게 테스트했습니다.
첫 번째 추가된 거래소 객체는 참조 거래소이며, 모든 거래소는 이 거래소 계정을 따라 작업을 수행합니다. OKEX 모형판 페이지에서, 참조 거래소 계정을 통해 3개의 ETH의 분기 코인 내역 계약을 수동으로 실행하십시오.
실제 디스크가 참조 거래소 계좌 보유의 변화를 감지하고 작업을 수행하는 것을 볼 수 있습니다.
이 두 개의 계약에 대해 다시 평준화해 보겠습니다.
실제 판은 동작을 따라 2개의 계약을 동결합니다.
이 전략은 단순하고 이해하기 쉬운 방식으로 설계되었으며, 최적화가 이루어지지 않으며, 완성된 부분은 청구서시 자산 검사와 같은 세부 사항을 처리해야 합니다. 간단한 설계를 위해, 시장 가격 목록을 사용하십시오. 전략은 단지 학습 아이디어를 제공하며, 실제는 필요에 따라 자체적으로 최적화됩니다.
이 글은 멘토와 함께 작성되었습니다.
pw1013두 개의 다른 거래소가 서로 연결할 수 없습니다.
밍시1005발명가들은 언제 화폐를 짝짓기해서 선물 계약을 이룰 수 있을까요? 화폐와 오이티는 너무 적은 수수료를 지불하고, 고주파 로봇은 너무 많은 수수료를 지불하고 있습니다.
아클크이 경우, 우리는 Bitcoin USDT의
qqlove23이 글을 공유해 주셔서 감사합니다.
발명가들의 수량화 - 작은 꿈거래소의 계약 사양이 다를 수 있기 때문에 특정 상황에 따라 주문 코드를 조정할 수 있습니다.
pw1013제가 사용하는 비박스 거래소는 80%의 수수료를 받고 있으며 FMZ는 완벽하게 지원합니다.
pw1013제가 지금 사용하는 bibox 퓨처스는 다른 사람의 okx 거래소를 연결하고 싶다면 어디서 변경해야 할까요?
발명가들의 수량화 - 작은 꿈이 프로젝트의 핵심은 이 프로젝트의 목표가 무엇인지에 대한 것입니다.
발명가들의 수량화 - 작은 꿈이 거래소를 평가하기 위해 아직 거래소 관계자가 연락하지 않았습니다.