ফরেক্স হিজিং সবসময়ই পার্থক্য সনাক্ত করার জন্য ডিজাইন করা হয়, যখন পার্থক্যের সাথে সামঞ্জস্য থাকে তখন একক হিজিং খাওয়া হয়। এটি কি হ্যাংড-অন হিজিংয়ের জন্য ডিজাইন করা যেতে পারে? উত্তরটি হ্যাঁ। আজ পাঠকদের একটি হ্যাংড-অন হিজিংয়ের নকশা ধারণা এবং কোড প্রোটোটাইপ নিয়ে আসে।
একই বা একই শ্রেণীর পণ্যের বিভিন্ন বাজারে, যখন দুটি বাজারের বিনিময় বিক্রয় আদেশের পার্থক্য বেশি হয় তখন হেজিংয়ের সুযোগ তৈরি হয়। সাধারণভাবে, আমরা দামের পার্থক্য পূরণকারী বিনিময় আদেশগুলি খেয়ে ফেলব এবং হেজিং পজিশন ধরে রাখব। সুতরাং হেজিংয়ের উদ্দেশ্য দুটি, প্রথমটি হ'ল অর্ডারটি ধরে রাখা, দ্বিতীয়টি হ'ল যতটা সম্ভব নিশ্চিত করা যে একটি কেনা-বিক্রয়ের পার্থক্যটি আমাদের প্রত্যাশার সাথে সামঞ্জস্যপূর্ণ।
তারপর আমরা ট্রেডিংয়ের ধারণাটি ডিজাইন করি, যাতে A মার্কেটের অর্ডার পকেট ক্রয় এবং B মার্কেটের অর্ডার পকেট বিক্রয়ের মধ্যে অর্ডারগুলি সংযুক্ত করা হয়। তারপর আমাদের অ্যাকাউন্টের অর্ডারগুলি সনাক্ত করা হয়, এবং সনাক্ত করা অর্ডারগুলি পরবর্তী পদক্ষেপের জন্য প্রক্রিয়াজাত করা হয়। উদাহরণস্বরূপ, যদি কোনও অর্ডার পরিবর্তন হয় তবে অবিলম্বে ব্যালেন্সের জন্য বর্তমান হেরফের অবস্থানগুলি সনাক্ত করা হয়, ভবিষ্যতের বর্তমান হোল্ডিংয়ের অতিরিক্ত অবস্থানের জন্য পুনর্নির্মাণ বা স্থিতিস্থাপক অপারেশন করা হয়। হেরফের পরিমাণ বাড়ার সাথে সাথে পরবর্তী ডিসপ্লেতে ঝুলানোর সময় সামঞ্জস্য করা হয় এবং ডিসপ্লেতে প্রথম অর্ডারটির তুলনায় আরও বড় ব্যবধানের দিকে ধীরে ধীরে হেরফের আনা হয়।
প্রতিবন্ধকতা
নোটগুলি সরাসরি কোডে লেখা হয়, এই উদাহরণটি শুধুমাত্র রেফারেন্স ডিজাইনের জন্য এবং শুধুমাত্র OKEX V5 অ্যালগরিদম ড্রাইভে সহজভাবে পরীক্ষা করা হয়েছে। এই উদাহরণটি একটি সম্পূর্ণ কৌশল নয়, কেবলমাত্র রেফারেন্সের জন্য ব্যবহার করুন।
// 临时参数
var fuContractType = "quarter" // 期货合约
var fuSymbol = "ETH_USDT" // 期货交易对
var spSymbol = "ETH_USDT" // 现货交易对
var minAmount = 0.1 // 每次交易量、最小交易量,币数
var step = 40 // 差价步长
var buff = 5 // 缓冲差价
var balanceType = "open" // 对于单腿成交平衡时, open 补仓 close 平仓
var depthManager = function(fuEx, spEx, fuCt, fuSymbol, spSymbol) {
var self = {}
self.fuExDepth = null
self.spExDepth = null
self.plusPrice = null
self.minusPrice = null
self.update = function() {
spEx.SetCurrency(spSymbol)
if (!IsVirtual()) {
fuEx.SetCurrency(fuSymbol)
}
fuEx.SetContractType(fuCt)
var fuRoutine = fuEx.Go("GetDepth")
var spRoutine = spEx.Go("GetDepth")
var fuDepth = fuRoutine.wait()
var spDepth = spRoutine.wait()
if (!fuDepth || !spDepth) {
return false
}
self.fuExDepth = fuDepth
self.spExDepth = spDepth
if (fuDepth.Bids.length == 0 || fuDepth.Asks.length == 0 || spDepth.Bids.length == 0 || spDepth.Asks.length == 0) {
return false
}
self.plusPrice = fuDepth.Bids[0].Price - spDepth.Asks[0].Price // futures Bid - spot Ask
self.minusPrice = fuDepth.Asks[0].Price - spDepth.Bids[0].Price // futures Ask - spot Bid
return true
}
self.getData = function() {
return {
"fuExDepth" : self.fuExDepth,
"spExDepth" : self.spExDepth,
"plusPrice" : self.plusPrice,
"minusPrice" : self.minusPrice
}
}
return self
}
var positionManager = function(fuEx, spEx, fuCt, fuSymbol, spSymbol, step, buffDiff, balanceType, initSpAcc) {
var self = {}
self.balanceType = balanceType
self.depth = null
self.level = 1
self.lastUpdateTs = 0
self.fuPos = []
self.spPos = []
self.initSpAcc = initSpAcc
self.spAcc = null
self.hedgePos = null
self.hedgePosPrice = 0
self.minAmount = 0.01
self.offset = ["", 0]
self.update = function() {
spEx.SetCurrency(spSymbol)
if (!IsVirtual()) {
fuEx.SetCurrency(fuSymbol)
}
fuEx.SetContractType(fuCt)
self.offset = ["", 0]
var fuRoutine = fuEx.Go("GetPosition")
var spRoutine = spEx.Go("GetAccount")
var fuPos = fuRoutine.wait()
var spAcc = spRoutine.wait()
if (!fuPos || !spAcc) {
return false
}
self.fuPos = fuPos
self.spAcc = spAcc
if (!self.initSpAcc) {
return false
}
self.spPos = (spAcc.Stocks + spAcc.FrozenStocks) - (self.initSpAcc.Stocks + self.initSpAcc.FrozenStocks) // 当前减去最初,正数为做多
// 检测fuPos
if (fuPos.length > 1) {
return false
}
fuPosAmount = fuPos.length == 0 ? 0 : (fuPos[0].Type == PD_LONG ? fuPos[0].Amount : -fuPos[0].Amount)
if ((fuPosAmount > 0 && self.spPos > 0) || (fuPosAmount < 0 && self.spPos < 0)) {
return false
}
fuPosAmount = self.piece2Coin(fuPosAmount)
self.hedgePos = (fuPosAmount == 0 || self.spPos == 0) ? 0 : (fuPosAmount < 0 && self.spPos > 0 ? Math.min(Math.abs(fuPosAmount), Math.abs(self.spPos)) : -Math.min(Math.abs(fuPosAmount), Math.abs(self.spPos)))
var diffBalance = (spAcc.Balance + spAcc.FrozenBalance) - (self.initSpAcc.Balance + self.initSpAcc.FrozenBalance)
if (self.hedgePos == 0) {
self.hedgePosPrice = 0
} else {
self.hedgePosPrice = fuPos[0].Price - (Math.abs(diffBalance) / Math.abs(self.spPos))
}
self.offset[1] = fuPosAmount + self.spPos // 正数多头持仓溢出,负数空头持仓溢出
if (fuPosAmount > 0 && self.spPos < 0) { // 反套
self.offset[0] = "minus"
} else if (fuPosAmount < 0 && self.spPos > 0) {
self.offset[0] = "plus"
} else if (fuPosAmount == 0 && self.spPos < 0) {
self.offset[0] = "minus"
} else if (fuPosAmount > 0 && self.spPos == 0) {
self.offset[0] = "minus"
} else if (fuPosAmount == 0 && self.spPos > 0) {
self.offset[0] = "plus"
} else if (fuPosAmount < 0 && self.spPos == 0) {
self.offset[0] = "plus"
}
return true
}
self.getData = function() {
return {
"fuPos" : self.fuPos,
"spPos" : self.spPos,
"initSpAcc" : self.initSpAcc,
"spAcc" : self.spAcc,
"hedgePos" : self.hedgePos,
"hedgePosPrice" : self.hedgePosPrice,
}
}
self.keepBalance = function(depth) {
var fuDepth = depth.fuExDepth
var spDepth = depth.spExDepth
if (self.offset[0] == "plus") {
if (self.offset[1] >= self.minAmount) {
if (self.balanceType == "close") {
// 现货多头持仓多了,平现货多仓
spEx.Sell(-1, self.offset[1])
} else if (self.balanceType == "open") {
// 现货多头持仓多了,开期货空头持仓
fuEx.SetDirection("sell")
fuEx.Sell(-1, self.coin2Piece(Math.abs(self.offset[1])))
}
} else if (self.offset[1] <= -self.minAmount) {
if (self.balanceType == "close") {
// 期货空头持仓多了,平期货空仓
fuEx.SetDirection("closesell")
fuEx.Buy(-1, self.coin2Piece(Math.abs(self.offset[1])))
} else if (self.balanceType == "open") {
// 期货空头持仓多了,开现货多头持仓
spEx.Buy(-1, spDepth.Asks[0].Price * Math.abs(self.offset[1]))
}
}
return false
} else if (self.offset[0] == "minus") {
if (self.offset[1] >= self.minAmount) {
if (self.balanceType == "close") {
// 期货多头持仓多了,平期货多仓
fuEx.SetDirection("closebuy")
fuEx.Sell(-1, self.coin2Piece(self.offset[1]))
} else if (self.balanceType == "open") {
// 期货多头持仓多了,开现货空头持仓
spEx.Sell(-1, self.offset[1])
}
} else if (self.offset[1] <= -self.minAmount) {
if (self.balanceType == "close") {
// 现货空头持仓多了,平现货空仓
spEx.Buy(-1, spDepth.Asks[0].Price * Math.abs(self.offset[1]))
} else if (self.balanceType == "open") {
// 现货空头持仓多了,开期货多头持仓
fuEx.SetDirection("buy")
fuEx.Buy(-1, self.coin2Piece(Math.abs(self.offset[1])))
}
}
return false
}
return true
}
self.process = function(depthManager) {
var ts = new Date().getTime()
var depth = depthManager.getData()
var orders = self.getOrders()
if (!orders) {
return
}
self.depth = depth
var fuOrders = orders[0]
var spOrders = orders[1]
if (fuOrders.length == 0 && spOrders.length == 0) {
// 重置level
if (self.hedgePos == 0) {
self.level = 1
} else {
self.level = Math.max(1, _N(self.hedgePos / self.minAmount, 0))
}
// 限制最大持仓量
if (Math.abs(self.hedgePos) > 1) {
return
}
// 挂单
var fuDepth = depth.fuExDepth
var spDepth = depth.spExDepth
self.update()
if (self.hedgePos >= 0 && fuDepth.Bids[0].Price - spDepth.Asks[0].Price > 0) { // 正套
var distance = (step * self.level - (fuDepth.Asks[0].Price - spDepth.Bids[0].Price)) / 2
fuEx.SetDirection("sell")
fuEx.Sell(fuDepth.Asks[0].Price + distance, self.coin2Piece(self.minAmount), fuDepth.Asks[0].Price, "挂单差价:", fuDepth.Asks[0].Price + distance - (spDepth.Bids[0].Price - distance))
spEx.Buy(spDepth.Bids[0].Price - distance, self.minAmount, spDepth.Bids[0].Price)
} else if (self.hedgePos <= 0 && spDepth.Bids[0].Price - fuDepth.Asks[0].Price > 0) { // 反套
var distance = (step * self.level - (spDepth.Asks[0].Price - fuDepth.Bids[0].Price)) / 2
fuEx.SetDirection("buy")
fuEx.Buy(fuDepth.Bids[0].Price - distance, self.coin2Piece(self.minAmount), fuDepth.Bids[0].Price, "挂单差价:", spDepth.Asks[0].Price + distance - (fuDepth.Bids[0].Price - distance))
spEx.Sell(spDepth.Asks[0].Price + distance, self.minAmount, spDepth.Asks[0].Price)
}
} else if (fuOrders.length == 1 && spOrders.length == 1) {
var fuDepth = depth.fuExDepth
var spDepth = depth.spExDepth
// 判断位置
var isCancelAll = false
if (self.hedgePos >= 0 && fuDepth.Bids[0].Price - spDepth.Asks[0].Price > 0) { // 正套
var distance = (step * self.level - (fuDepth.Asks[0].Price - spDepth.Bids[0].Price)) / 2
if (Math.abs(fuOrders[0].Price - (fuDepth.Asks[0].Price + distance)) > buffDiff || Math.abs(spOrders[0].Price - (spDepth.Bids[0].Price - distance)) > buffDiff) {
isCancelAll = true
}
} else if (self.hedgePos <= 0 && spDepth.Bids[0].Price - fuDepth.Asks[0].Price > 0) { // 反套
var distance = (step * self.level - (spDepth.Asks[0].Price - fuDepth.Bids[0].Price)) / 2
if (Math.abs(spOrders[0].Price - (spDepth.Asks[0].Price + distance)) > buffDiff || Math.abs(fuOrders[0].Price - (fuDepth.Bids[0].Price - distance)) > buffDiff) {
isCancelAll = true
}
} else {
isCancelAll = true
}
if (isCancelAll) {
self.cancelAll(fuEx, fuOrders)
self.cancelAll(spEx, spOrders)
self.lastUpdateTs = 0
}
} else {
self.cancelAll(fuEx, fuOrders)
self.cancelAll(spEx, spOrders)
self.lastUpdateTs = 0
}
if (ts - self.lastUpdateTs > 1000 * 60 * 2) {
self.update()
self.keepBalance(depth)
self.update()
self.lastUpdateTs = ts
}
LogStatus(_D()) // 状态栏可以设计输出需要观察的数据、信息
}
self.getOrders = function() {
spEx.SetCurrency(spSymbol)
if (!IsVirtual()) {
fuEx.SetCurrency(fuSymbol)
}
fuEx.SetContractType(fuCt)
var fuRoutine = fuEx.Go("GetOrders")
var spRoutine = spEx.Go("GetOrders")
var fuOrders = fuRoutine.wait()
var spOrders = spRoutine.wait()
if (!fuOrders || !spOrders) {
return false
}
return [fuOrders, spOrders]
}
// 币转合约张数
self.coin2Piece = function(amount) {
if (IsVirtual()) {
if (fuEx.GetName() == "Futures_Binance") {
return amount
} else if (fuEx.GetName() == "Futures_OKCoin") {
var price = (self.depth.fuExDepth.Bids[0].Price + self.depth.fuExDepth.Asks[0].Price) / 2
return _N(amount / (100 / price), 0)
} else {
throw "not support"
}
}
if (fuEx.GetName() == "Futures_OKCoin") {
if (fuEx.GetQuoteCurrency() == "USDT") {
return _N(amount * 10, 0)
} else if (fuEx.GetQuoteCurrency() == "USD") {
var price = (self.depth.fuExDepth.Bids[0].Price + self.depth.fuExDepth.Asks[0].Price) / 2
return _N(amount / (100 / price), 0)
} else {
throw "not support"
}
} else {
throw "not support"
}
}
// 合约张数转币
self.piece2Coin = function(amount) {
if (IsVirtual()) {
if (fuEx.GetName() == "Futures_Binance") {
return amount
} else if (fuEx.GetName() == "Futures_OKCoin") {
var price = (self.depth.fuExDepth.Bids[0].Price + self.depth.fuExDepth.Asks[0].Price) / 2
return amount * 100 / price
} else {
throw "not support"
}
}
if (fuEx.GetName() == "Futures_OKCoin") {
if (fuEx.GetQuoteCurrency() == "USDT") {
return amount * 0.1
} else if (fuEx.GetQuoteCurrency() == "USD") {
var price = (self.depth.fuExDepth.Bids[0].Price + self.depth.fuExDepth.Asks[0].Price) / 2
return amount * 100 / price
} else {
throw "not support"
}
} else {
throw "not support"
}
}
self.cancelAll = function(e, orders) {
var isFirst = true
while (true) {
Sleep(500)
if (orders && isFirst) {
isFirst = false
} else {
orders = e.GetOrders()
}
if (!orders) {
continue
} else {
for (var i = 0 ; i < orders.length ; i++) {
e.CancelOrder(orders[i].Id, orders[i])
}
}
if (orders.length == 0) {
break
}
}
}
self.CoverAll = function() {
// 全部平仓
// 这里可以实现一个,一键平仓的功能
}
self.setMinAmount = function(minAmount) {
self.minAmount = minAmount
}
self.init = function() {
while(!self.spAcc) {
self.update()
Sleep(1000)
}
if (!self.initSpAcc) {
var positionManager_initSpAcc = _G("positionManager_initSpAcc")
if (!positionManager_initSpAcc) {
self.initSpAcc = self.spAcc
_G("positionManager_initSpAcc", self.initSpAcc)
} else {
self.initSpAcc = positionManager_initSpAcc
}
} else {
_G("positionManager_initSpAcc", self.initSpAcc)
}
// 打印初始信息
Log("self.initSpAcc:", self.initSpAcc.Balance, self.initSpAcc.FrozenBalance, self.initSpAcc.Stocks, self.initSpAcc.FrozenStocks)
}
self.init()
return self
}
function main() {
_G(null) // 清空持久化数据
LogReset(1) // 重置日志
// 以下代码可以切换OKEX模拟盘
// exchanges[0].IO("simulate", true)
// exchanges[1].IO("simulate", true)
var dm = depthManager(exchanges[0], exchanges[1], fuContractType, fuSymbol, spSymbol)
var pm = positionManager(exchanges[0], exchanges[1], fuContractType, fuSymbol, spSymbol, step, buff, balanceType)
pm.setMinAmount(minAmount)
while (true) {
if (!dm.update()) {
Sleep(3000)
continue
}
var cmd = GetCommand()
if (cmd) {
// 处理交互
Log("交互命令:", cmd)
var arr = cmd.split(":")
if (arr[0] == "") {
pm.CoverAll()
}
}
pm.process(dm)
Sleep(5000)
}
}
আপনি দেখতে পাচ্ছেন যে আটকানো, প্রত্যাহার করা খুব ঘন ঘন। রিভিউ সিস্টেমের পরিসংখ্যান থেকে দেখা যায় যে ফিউচার এক্সচেঞ্জের অ্যাকাউন্টটি ক্ষতিগ্রস্থ হয়েছে - 0.01666 ইটিএইচ, এবং অবিলম্বে এক্সচেঞ্জটি 842.23758 ইউএসডিটি লাভ করেছে। রিভিউ শেষে ইটিএইচ অবিলম্বে মূল্য 4252 ইউএসডিটি ছিল, যা প্রায়শই হ্রাস পায়।-0.01666 * 4252 = -70.83832000000001
⇒ ⇒ ⇒ ⇒ ⇒ ⇒
তবে এটি কেবলমাত্র একটি রিভিউ, এবং বাস্তব সময়ে অবশ্যই আরও বিস্তারিত সমস্যাগুলি সমাধান করা উচিত।
সিলিকনড্রিম সামগ্রিকভাবে, ওকেএক্স ইউনিফাইড অ্যাকাউন্ট মোড সমর্থন করে না।
৮১৩৩৮০৬২৯গরু
উদ্ভাবকগণ - ক্যোটিফিকেশন - ছোট্ট স্বপ্নহ্যালো, ওকেএক্স ভি 5 ইন্টারফেস সমর্থনকারীরা এই মোডটি সমর্থন করে।