Kali ini, strategi yang dibawa oleh FMZ Quant adalahPendapatan yang tidak terhitung jumlahnya, disingkat sebagai DDH.
Model penetapan harga opsi; model B-S; harga opsi ditentukan berdasarkan
Eksposur risiko opsi:
Penjelasan Prinsip DDH Dengan menyeimbangkan delta opsi dan berjangka, netralitas risiko arah perdagangan dicapai. Karena delta opsi berubah seiring perubahan harga yang mendasari, delta futures dan spot tidak akan berubah. Setelah memegang posisi kontrak opsi dan menggunakan berjangka untuk lindung nilai dan menyeimbangkan Delta, karena perubahan harga yang mendasari, keseluruhan Delta akan muncul tidak seimbang lagi.
Misalnya: Saat kita membeli opsi panggilan, kita memiliki posisi bullish. pada saat ini, perlu untuk short futures untuk lindung nilai opsi Delta untuk mencapai netralitas Delta secara keseluruhan (0 atau dekat dengan 0). Mari kita abaikan faktor-faktor, seperti hari sampai kadaluarsa dan volatilitas tersirat dari kontrak opsi. Skenario 1: Ketika harga yang mendasari naik, opsi Delta meningkat, dan keseluruhan Delta bergerak ke angka positif. Futures diperlukan untuk lindung nilai lagi, dan beberapa posisi pendek dibuka untuk melanjutkan ke futures pendek, sehingga keseluruhan Delta seimbang lagi. (Sebelum menyeimbangkan kembali, delta opsi besar, delta berjangka relatif kecil, keuntungan marginal dari opsi panggilan melebihi kerugian marginal dari kontrak pendek, dan seluruh portofolio akan menghasilkan keuntungan.) Skenario 2: Ketika harga yang mendasari jatuh, delta opsi menurun, dan delta keseluruhan bergerak ke angka negatif, dan beberapa posisi berjangka pendek ditutup untuk membuat keseimbangan delta keseluruhan lagi. (Sebelum menyeimbangkan kembali, delta opsi kecil, delta berjangka relatif besar, kerugian marginal dari opsi panggilan kurang dari keuntungan marginal dari kontrak pendek, dan seluruh portofolio masih akan memiliki keuntungan.)
Oleh karena itu, idealnya, naik dan turun dari dasar kedua membawa keuntungan, selama pasar berfluktuasi.
Namun, ada faktor lain yang perlu dipertimbangkan: nilai waktu, biaya perdagangan dan lain-lain.
Jadi, saya mengutip penjelasan seorang master dari Zhihu:
Fokus dari Gamma Scalping bukanlah delta, dynamic delta hedging hanyalah cara untuk menghindari risiko harga yang mendasari dalam prosesnya. Gamma Scalping berfokus pada Alpha. Alpha bukanlah Alpha dari seleksi saham. Di sini, Alpha = Gamma/Theta, yaitu berapa banyak Gamma yang ditukarkan dengan penurunan waktu unit Theta. Itulah intinya. Adalah mungkin untuk membangun kombinasi kenaikan dan penurunan baik dengan keuntungan mengambang, pasti disertai dengan penurunan waktu, dan masalahnya adalah rasio kinerja biaya. Penulis: Xu Zhe; link artikel asli:https://www.zhihu.com/question/51630805/answer/128096385
Kode sumber:
// constructor
function createManager(e, subscribeList, msg) {
var self = {}
self.supportList = ["Futures_Binance", "Huobi", "Futures_Deribit"] // from the supported platforms
// object attributes
self.e = e
self.msg = msg
self.name = e.GetName()
self.type = self.name.includes("Futures_") ? "Futures" : "Spot"
self.label = e.GetLabel()
self.quoteCurrency = ""
self.subscribeList = subscribeList // subscribeList : [strSymbol1, strSymbol2, ...]
self.tickers = [] // all market data obtained by the interface; define the data format as: {bid1: 123, ask1: 123, symbol: "xxx"}}
self.subscribeTickers = [] // the market data in need; define the data format as: {bid1: 123, ask1: 123, symbol: "xxx"}}
self.accData = null
self.pos = null
// initialization function
self.init = function() {
// judge whether the platform is supported
if (!_.contains(self.supportList, self.name)) {
throw "not support"
}
}
self.setBase = function(base) {
// switch base address, used to switch to the simulated bot
self.e.SetBase(base)
Log(self.name, self.label, "switch to simulated bot:", base)
}
// judge the data precision
self.judgePrecision = function (p) {
var arr = p.toString().split(".")
if (arr.length != 2) {
if (arr.length == 1) {
return 0
}
throw "judgePrecision error, p:" + String(p)
}
return arr[1].length
}
// update assets
self.updateAcc = function(callBackFuncGetAcc) {
var ret = callBackFuncGetAcc(self)
if (!ret) {
return false
}
self.accData = ret
return true
}
// update positions
self.updatePos = function(httpMethod, url, params) {
var pos = self.e.IO("api", httpMethod, url, params)
var ret = []
if (!pos) {
return false
} else {
// arrange data
// {"jsonrpc":"2.0","result":[],"usIn":1616484238870404,"usOut":1616484238870970,"usDiff":566,"testnet":true}
try {
_.each(pos.result, function(ele) {
ret.push(ele)
})
} catch(err) {
Log("error:", err)
return false
}
self.pos = ret
}
return true
}
// update the market data
self.updateTicker = function(url, callBackFuncGetArr, callBackFuncGetTicker) {
var tickers = []
var subscribeTickers = []
var ret = self.httpQuery(url)
if (!ret) {
return false
}
// Log("test", ret)// test
try {
_.each(callBackFuncGetArr(ret), function(ele) {
var ticker = callBackFuncGetTicker(ele)
tickers.push(ticker)
if (self.subscribeList.length == 0) {
subscribeTickers.push(ticker)
} else {
for (var i = 0 ; i < self.subscribeList.length ; i++) {
if (self.subscribeList[i] == ticker.symbol) {
subscribeTickers.push(ticker)
}
}
}
})
} catch(err) {
Log("error:", err)
return false
}
self.tickers = tickers
self.subscribeTickers = subscribeTickers
return true
}
self.getTicker = function(symbol) {
var ret = null
_.each(self.subscribeTickers, function(ticker) {
if (ticker.symbol == symbol) {
ret = ticker
}
})
return ret
}
self.httpQuery = function(url) {
var ret = null
try {
var retHttpQuery = HttpQuery(url)
ret = JSON.parse(retHttpQuery)
} catch (err) {
// Log("error:", err)
ret = null
}
return ret
}
self.returnTickersTbl = function() {
var tickersTbl = {
type : "table",
title : "tickers",
cols : ["symbol", "ask1", "bid1"],
rows : []
}
_.each(self.subscribeTickers, function(ticker) {
tickersTbl.rows.push([ticker.symbol, ticker.ask1, ticker.bid1])
})
return tickersTbl
}
// return the positon table
self.returnPosTbl = function() {
var posTbl = {
type : "table",
title : "pos|" + self.msg,
cols : ["instrument_name", "mark_price", "direction", "size", "delta", "index_price", "average_price", "settlement_price", "average_price_usd", "total_profit_loss"],
rows : []
}
/* the position data format returned by the interface
{
"mark_price":0.1401105,"maintenance_margin":0,"instrument_name":"BTC-25JUN21-28000-P","direction":"buy",
"vega":5.66031,"total_profit_loss":0.01226105,"size":0.1,"realized_profit_loss":0,"delta":-0.01166,"kind":"option",
"initial_margin":0,"index_price":54151.77,"floating_profit_loss_usd":664,"floating_profit_loss":0.000035976,
"average_price_usd":947.22,"average_price":0.0175,"theta":-7.39514,"settlement_price":0.13975074,"open_orders_margin":0,"gamma":0
}
*/
_.each(self.pos, function(ele) {
if(ele.direction != "zero") {
posTbl.rows.push([ele.instrument_name, ele.mark_price, ele.direction, ele.size, ele.delta, ele.index_price, ele.average_price, ele.settlement_price, ele.average_price_usd, ele.total_profit_loss])
}
})
return posTbl
}
self.returnOptionTickersTbls = function() {
var arr = []
var arrDeliveryDate = []
_.each(self.subscribeTickers, function(ticker) {
if (self.name == "Futures_Deribit") {
var arrInstrument_name = ticker.symbol.split("-")
var currency = arrInstrument_name[0]
var deliveryDate = arrInstrument_name[1]
var deliveryPrice = arrInstrument_name[2]
var optionType = arrInstrument_name[3]
if (!_.contains(arrDeliveryDate, deliveryDate)) {
arr.push({
type : "table",
title : arrInstrument_name[1],
cols : ["PUT symbol", "ask1", "bid1", "mark_price", "underlying_price", "CALL symbol", "ask1", "bid1", "mark_price", "underlying_price"],
rows : []
})
arrDeliveryDate.push(arrInstrument_name[1])
}
// traverse arr
_.each(arr, function(tbl) {
if (tbl.title == deliveryDate) {
if (tbl.rows.length == 0 && optionType == "P") {
tbl.rows.push([ticker.symbol, ticker.ask1, ticker.bid1, ticker.mark_price, ticker.underlying_price, "", "", "", "", ""])
return
} else if (tbl.rows.length == 0 && optionType == "C") {
tbl.rows.push(["", "", "", "", "", ticker.symbol, ticker.ask1, ticker.bid1, ticker.mark_price, ticker.underlying_price])
return
}
for (var i = 0 ; i < tbl.rows.length ; i++) {
if (tbl.rows[i][0] == "" && optionType == "P") {
tbl.rows[i][0] = ticker.symbol
tbl.rows[i][1] = ticker.ask1
tbl.rows[i][2] = ticker.bid1
tbl.rows[i][3] = ticker.mark_price
tbl.rows[i][4] = ticker.underlying_price
return
} else if(tbl.rows[i][5] == "" && optionType == "C") {
tbl.rows[i][5] = ticker.symbol
tbl.rows[i][6] = ticker.ask1
tbl.rows[i][7] = ticker.bid1
tbl.rows[i][8] = ticker.mark_price
tbl.rows[i][9] = ticker.underlying_price
return
}
}
if (optionType == "P") {
tbl.rows.push([ticker.symbol, ticker.ask1, ticker.bid1, ticker.mark_price, ticker.underlying_price, "", "", "", "", ""])
} else if(optionType == "C") {
tbl.rows.push(["", "", "", "", "", ticker.symbol, ticker.ask1, ticker.bid1, ticker.mark_price, ticker.underlying_price])
}
}
})
}
})
return arr
}
// initialize
self.init()
return self
}
function main() {
// initialize, and vacuum logs
if(isResetLog) {
LogReset(1)
}
var m1 = createManager(exchanges[0], [], "option")
var m2 = createManager(exchanges[1], ["BTC-PERPETUAL"], "future")
// switch to the simulated bot
var base = "https://www.deribit.com"
if (isTestNet) {
m1.setBase(testNetBase)
m2.setBase(testNetBase)
base = testNetBase
}
while(true) {
// options
var ticker1GetSucc = m1.updateTicker(base + "/api/v2/public/get_book_summary_by_currency?currency=BTC&kind=option",
function(data) {return data.result},
function(ele) {return {bid1: ele.bid_price, ask1: ele.ask_price, symbol: ele.instrument_name, underlying_price: ele.underlying_price, mark_price: ele.mark_price}})
// perpetual futures
var ticker2GetSucc = m2.updateTicker(base + "/api/v2/public/get_book_summary_by_currency?currency=BTC&kind=future",
function(data) {return data.result},
function(ele) {return {bid1: ele.bid_price, ask1: ele.ask_price, symbol: ele.instrument_name}})
if (!ticker1GetSucc || !ticker2GetSucc) {
Sleep(5000)
continue
}
// update positions
var pos1GetSucc = m1.updatePos("GET", "/api/v2/private/get_positions", "currency=BTC&kind=option")
var pos2GetSucc = m2.updatePos("GET", "/api/v2/private/get_positions", "currency=BTC&kind=future")
if (!pos1GetSucc || !pos2GetSucc) {
Sleep(5000)
continue
}
// interaction
var cmd = GetCommand()
if(cmd) {
// process interaction
Log("interactive command:", cmd)
var arr = cmd.split(":")
// cmdClearLog
if(arr[0] == "setContractType") {
// parseFloat(arr[1])
m1.e.SetContractType(arr[1])
Log("exchanges[0] sets contract:", arr[1])
} else if (arr[0] == "buyOption") {
var actionData = arr[1].split(",")
var price = parseFloat(actionData[0])
var amount = parseFloat(actionData[1])
m1.e.SetDirection("buy")
m1.e.Buy(price, amount)
Log("executed price:", price, "executed amount:", amount, "executed direction:", arr[0])
} else if (arr[0] == "sellOption") {
var actionData = arr[1].split(",")
var price = parseFloat(actionData[0])
var amount = parseFloat(actionData[1])
m1.e.SetDirection("sell")
m1.e.Sell(price, amount)
Log("executed price:", price, "executed amount:", amount, "executed direction:", arr[0])
} else if (arr[0] == "setHedgeDeltaStep") {
hedgeDeltaStep = parseFloat(arr[1])
Log("set hedgeDeltaStep:", hedgeDeltaStep)
}
}
// obtain futures contract price
var perpetualTicker = m2.getTicker("BTC-PERPETUAL")
var hedgeMsg = " PERPETUAL:" + JSON.stringify(perpetualTicker)
// obtain the total delta value from the account data
var acc1GetSucc = m1.updateAcc(function(self) {
self.e.SetCurrency("BTC_USD")
return self.e.GetAccount()
})
if (!acc1GetSucc) {
Sleep(5000)
continue
}
var sumDelta = m1.accData.Info.result.delta_total
if (Math.abs(sumDelta) > hedgeDeltaStep && perpetualTicker) {
if (sumDelta < 0) {
// delta value is more than 0, hedge futures and make short
var amount = _N(Math.abs(sumDelta) * perpetualTicker.ask1, -1)
if (amount > 10) {
Log("exceeding the hedging threshold value, the current total delta:", sumDelta, "call futures")
m2.e.SetContractType("BTC-PERPETUAL")
m2.e.SetDirection("buy")
m2.e.Buy(-1, amount)
} else {
hedgeMsg += ", hedging order amount is less than 10"
}
} else {
// delta value is less than 0, hedge futures and make long
var amount = _N(Math.abs(sumDelta) * perpetualTicker.bid1, -1)
if (amount > 10) {
Log("exceeding the hedging threshold value, the current total delta:", sumDelta, "put futures")
m2.e.SetContractType("BTC-PERPETUAL")
m2.e.SetDirection("sell")
m2.e.Sell(-1, amount)
} else {
hedgeMsg += ", hedging order amount is less than 0"
}
}
}
LogStatus(_D(), "sumDelta:", sumDelta, hedgeMsg,
"\n`" + JSON.stringify([m1.returnPosTbl(), m2.returnPosTbl()]) + "`", "\n`" + JSON.stringify(m2.returnTickersTbl()) + "`", "\n`" + JSON.stringify(m1.returnOptionTickersTbls()) + "`")
Sleep(10000)
}
}
Parameter strategi:
Alamat strategi:https://www.fmz.com/strategy/265090
Strategi ini adalah tutorial, terutama digunakan untuk belajar, jadi berhati-hatilah menggunakan dalam bot.