Teaching Deribit Options Delta Dynamic Hedging Strategy
Article address:https://www.fmz.com/bbs-topic/6726
JavaScriptOther
DeribitOptions Delta dynamic hedging strategy (tutorial))
Article address:https://www.fmz.com/bbs-topic/6726
Parameters
| Name | Default | What it controls |
|---|---|---|
| isTestNet | true | Whether to switch to simulated disk |
| testNetBase | https://test.deribit.com | Simulated account base address |
| hedgeDeltaStep | true | DeltaHedge Step |
| isResetLog | true | Clear logs or not |
| Button | Default | Description |
| ---- | ---- | ---- |
| setContractType | Set option contract | |
| buyOption | Buy option contract | |
| sellOption | Sell option contract | |
| setHedgeDeltaStep | true | Set hedge threshold |
Source JavaScript
// Constructor
function createManager(e, subscribeList, msg) {
var self = {}
self.supportList = ["Futures_Binance", "Huobi", "Futures_Deribit"] // Supported exchanges
// 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 from the API, define the data format:{bid1: 123, ask1: 123, symbol: "xxx"}}
self.subscribeTickers = [] // required market data, define the data format:{bid1: 123, ask1: 123, symbol: "xxx"}}
self.accData = null
self.pos = null
// Initialization function
self.init = function() {
// Determine whether the exchange is supported
if (!_.contains(self.supportList, self.name)) {
throw "not support"
}
}
self.setBase = function(base) {
// switch the base address, used to switch to the demo account
self.e.SetBase(base)
Log(self.name, self.label, "Switch to simulated account:", base)
}
// Determine 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 {
// Organize 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 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 positions 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 : []
}
/* 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])
}
// Iteratearr
_.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() {
// Initialization, clear log
if(isResetLog) {
LogReset(1)
}
var m1 = createManager(exchanges[0], [], "option")
var m2 = createManager(exchanges[1], ["BTC-PERPETUAL"], "future")
// Switch to simulated account
var base = "https://www.deribit.com"
if (isTestNet) {
m1.setBase(testNetBase)
m2.setBase(testNetBase)
base = testNetBase
}
while(true) {
// Option
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) {
// Handle Interaction
Log("Interaction Commands:", cmd)
var arr = cmd.split(":")
// cmdClearLog
if(arr[0] == "setContractType") {
// parseFloat(arr[1])
m1.e.SetContractType(arr[1])
Log("exchanges[0]Exchange object 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("Execution Price:", price, "Execution Quantity:", amount, "Execution 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("Execution Price:", price, "Execution Quantity:", amount, "Execution Direction:", arr[0])
} else if (arr[0] == "setHedgeDeltaStep") {
hedgeDeltaStep = parseFloat(arr[1])
Log("Set ParametershedgeDeltaStep:", hedgeDeltaStep)
}
}
// Get futures contract price
var perpetualTicker = m2.getTicker("BTC-PERPETUAL")
var hedgeMsg = " PERPETUAL:" + JSON.stringify(perpetualTicker)
// Get from account datadeltaTotal Value
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 Greater than0 Hedge futures short
var amount = _N(Math.abs(sumDelta) * perpetualTicker.ask1, -1)
if (amount > 10) {
Log("Exceeding the hedge threshold, current totaldelta:", sumDelta, "Buy Futures")
m2.e.SetContractType("BTC-PERPETUAL")
m2.e.SetDirection("buy")
m2.e.Buy(-1, amount)
} else {
hedgeMsg += ", Hedge order volume less than10"
}
} else {
// delta Less Than0 Hedge futures long
var amount = _N(Math.abs(sumDelta) * perpetualTicker.bid1, -1)
if (amount > 10) {
Log("Exceeding the hedge threshold, current totaldelta:", sumDelta, "Sell Futures")
m2.e.SetContractType("BTC-PERPETUAL")
m2.e.SetDirection("sell")
m2.e.Sell(-1, amount)
} else {
hedgeMsg += ", Hedge order volume less than10"
}
}
}
LogStatus(_D(), "sumDelta:", sumDelta, hedgeMsg,
"\n`" + JSON.stringify([m1.returnPosTbl(), m2.returnPosTbl()]) + "`", "\n`" + JSON.stringify(m2.returnTickersTbl()) + "`", "\n`" + JSON.stringify(m1.returnOptionTickersTbls()) + "`")
Sleep(10000)
}
}
Published by 发明者量化-小小梦 on the FMZ strategy square · last modified 2021-03-29. Collected in the Quant Trading Vault. Unvalidated research: re-test with your own data and costs before trusting it.
Build this with AgenKit
A spec is not a trading system. Paste this into your coding agent and AgenKit runs a specialist team — architecture, test-first build, risk gates, review — with paper trading on by default.
/agenkit build a production-grade trading bot with a backtest engine, risk controls and paper trading by default from strategies/Teaching-Deribit-Options-Delta-Dynamic-Hedging-Strategy.md- npx agenkit install engineering-kit in your project
- Paste the command into your agent and approve each phase
- Get tests, backtest, risk controls and a paper-trading switch
Understand it first
Before you run this, read the lesson behind the idea and how to backtest it honestly. Specs like this one are the survivors of an unknown number of trials; deflate their results accordingly.