4
Подписаться
1271
Подписчики

Deribit Option Delta Динамическая стратегия хеджирования

Создано: 2021-03-26 11:18:53, Обновлено: 2024-12-05 21:55:32
comments   6
hits   3894

Deribit Option Delta Динамическая стратегия хеджирования

Deribit Option Delta Динамическая стратегия хеджирования

Стратегия, предложенная этой количественной оценкой FMZ, заключается в следующем:Deribit Option Delta Динамическая стратегия хеджирования, называемая стратегией DDH (динамическое дельта-хеджирование).

При изучении торговли опционами нам обычно необходимо освоить следующие концепции:

  • Модель ценообразования опционов, модель B-S, цена опциона определяется на основе [цены базового актива], [цены исполнения], [оставшегося времени до истечения срока], [(подразумеваемой) волатильности] и [безрисковой процентной ставки].

  • Варианты экспозиции:

    • Дельта — направленный риск опциона. Если Дельта составляет +0,50, то прибыль и убыток по этому опциону при росте или падении базовой цены можно рассматривать как 0,50 спот.
    • Гамма — ускорение направленного риска. Например, для опциона колл, из-за эффекта Гаммы, начиная с момента, когда базовая цена достигнет цены страйк, по мере дальнейшего роста цены, Дельта будет постепенно изменяться от +0,50 до +1,00.
    • Тета — время экспозиции. При покупке опциона, если базовая цена не изменится, вы заплатите комиссию, размер которой определяется суммой Тета (дерибит, выраженный в долларах США) за каждый прошедший день. При продаже опциона, если базовая цена не изменится, вы получите комиссию, определяемую суммой Тета за каждый прошедший день.
    • Вега — подверженность волатильности. Когда вы покупаете опцион, Вега положительна, что означает, что у вас длинная позиция по волатильности. Когда подразумеваемая волатильность увеличивается, вы получаете выгоду от своей позиции Vega. И наоборот, когда вы продаете опционы, подразумеваемая волатильность уменьшается, и вы получаете прибыль.

Объяснение стратегии DDH:

  • Объяснение принципа DDH Путем балансировки дельты опционов и фьючерсов можно достичь нейтральности риска в направлении торговли. Поскольку дельта опционов будет меняться вместе с ценой базового актива, дельта фьючерсных и спотовых цен останется неизменной. После удержания позиции по опционному контракту и использования фьючерсов для хеджирования и балансировки дельты общая дельта снова станет несбалансированной, поскольку цена базового актива изменится. Для комбинации опционных позиций и фьючерсных позиций требуется постоянное динамическое хеджирование и балансировка Delta.

Например: Когда мы покупаем опцион колл, мы занимаем бычью позицию. В это время необходимо делать короткие продажи фьючерсов, чтобы хеджировать дельту опционов и достичь общей нейтральности дельты (0 или близкой к 0). На данный момент мы не будем учитывать такие факторы, как оставшееся время до истечения опционного контракта и волатильность. Случай 1: По мере роста цены базового актива дельта опционной части увеличивается, а общая дельта движется к положительному числу. Фьючерсы нужны для хеджирования снова, и часть коротких позиций должна быть открыта для продолжения коротких фьючерсов, чтобы сбалансировать снова общая Дельта. (До ребалансировки дельта опциона велика, тогда как дельта фьючерса относительно мала. Предельная прибыль опциона колл превышает предельный убыток короткого контракта, и весь портфель будет приносить прибыль.)

Случай 2: По мере падения цены базового актива дельта опционной части уменьшается, а общая дельта движется в сторону отрицательного числа, закрывая часть коротких фьючерсных позиций, чтобы снова сбалансировать общую дельту. (До ребалансировки дельта опциона невелика, тогда как дельта фьючерса относительно велика. Предельный убыток опциона колл меньше предельной прибыли короткого контракта, поэтому весь портфель по-прежнему будет приносить прибыль.)

Таким образом, в идеале и рост, и падение базового актива будут приносить прибыль, если только существуют рыночные колебания.

Однако необходимо учитывать и другие факторы: временную стоимость, транзакционные издержки и т. д.

Итак, цитирую пояснения экспертов Чжиху:

  Gamma Scalping 的关注点并不是delta,dynamic delta hedging 只是过程中规避underlying价格风险的一种做法而已。
  Gamma Scalping 关注的是Alpha,此Alpha不是选股的Alpha,这里的Alpha = Gamma/Theta也就是单位Theta的时间损耗换来多少Gamma,
  这个是关注的点。可以构建出上涨和下跌都浮盈的组合,但一定伴随时间损耗,那问题就在于性价比了。

  作者:许哲
  链接:https://www.zhihu.com/question/51630805/answer/128096385

Объяснение дизайна стратегии DDH

  • Инкапсуляция интерфейса совокупного рынка и проектирование фреймворка
  • Стратегия дизайна пользовательского интерфейса
  • Стратегическое проектирование взаимодействия
  • Автоматическая разработка функции хеджирования

Исходный код:

// 构造函数
function createManager(e, subscribeList, msg) {
	var self = {}
    self.supportList = ["Futures_Binance", "Huobi", "Futures_Deribit"]  // 支持的交易所的

    // 对象属性
    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 = []                    // 接口获取的所有行情数据,定义数据格式:{bid1: 123, ask1: 123, symbol: "xxx"}}
    self.subscribeTickers = []           // 需要的行情数据,定义数据格式:{bid1: 123, ask1: 123, symbol: "xxx"}}
    self.accData = null 
    self.pos = null 

    // 初始化函数
    self.init = function() { 
    	// 判断是否支持该交易所
        if (!_.contains(self.supportList, self.name)) {        	
        	throw "not support"
        }
    }

    self.setBase = function(base) {
        // 切换基地址,用于切换为模拟盘
        self.e.SetBase(base)
        Log(self.name, self.label, "切换为模拟盘:", base)
    }

    // 判断数据精度
    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
    }

    // 更新资产
    self.updateAcc = function(callBackFuncGetAcc) {
        var ret = callBackFuncGetAcc(self)
        if (!ret) {
        	return false 
        }
        self.accData = ret 
        return true 
    }

    // 更新持仓
    self.updatePos = function(httpMethod, url, params) {
        var pos = self.e.IO("api", httpMethod, url, params)
        var ret = []
        if (!pos) {
            return false 
        } else {
            // 整理数据
            // {"jsonrpc":"2.0","result":[],"usIn":1616484238870404,"usOut":1616484238870970,"usDiff":566,"testnet":true}
            try {
                _.each(pos.result, function(ele) {
                    ret.push(ele)
                })
            } catch(err) {
                Log("错误:", err)
                return false 
            }
            self.pos = ret
        }
        return true 
    }

    // 更新行情数据
    self.updateTicker = function(url, callBackFuncGetArr, callBackFuncGetTicker) {
    	var tickers = []
    	var subscribeTickers = []
    	var ret = self.httpQuery(url)
    	if (!ret) {
    		return false 
    	}
    	// Log("测试", ret)// 测试
    	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("错误:", 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("错误:", 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
    }
    
    // 返回持仓表格
    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 : []
        }
        /* 接口返回的持仓数据格式
        {
            "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])
                }
                // 遍历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 
    }

    // 初始化
    self.init()
	return self 
}


function main() {
    // 初始化,清空日志
    if(isResetLog) {
    	LogReset(1)
    }

    var m1 = createManager(exchanges[0], [], "option")
    var m2 = createManager(exchanges[1], ["BTC-PERPETUAL"], "future")

    // 切换为模拟盘
    var base = "https://www.deribit.com"
    if (isTestNet) {    
        m1.setBase(testNetBase)    
        m2.setBase(testNetBase)
        base = testNetBase
    }

    while(true) {
        // 期权
        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}}) 
        
        // 永续期货
        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
        }

        // 更新持仓
        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
        }

        // 交互
        var cmd = GetCommand()
        if(cmd) {
            // 处理交互
            Log("交互命令:", cmd)
            var arr = cmd.split(":")
            // cmdClearLog 
            if(arr[0] == "setContractType") {
                // parseFloat(arr[1])
                m1.e.SetContractType(arr[1])
                Log("exchanges[0]交易所对象设置合约:", 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("执行价格:", price, "执行数量:", amount, "执行方向:", 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("执行价格:", price, "执行数量:", amount, "执行方向:", arr[0])
            } else if (arr[0] == "setHedgeDeltaStep") {
                hedgeDeltaStep = parseFloat(arr[1])
                Log("设置参数hedgeDeltaStep:", hedgeDeltaStep)
            } 
        }
        
        // 获取期货合约价格
        var perpetualTicker = m2.getTicker("BTC-PERPETUAL")
        var hedgeMsg = " PERPETUAL:" + JSON.stringify(perpetualTicker)

        // 从账户数据中获取delta总值        
        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 大于0 对冲期货做空                
                var amount = _N(Math.abs(sumDelta) * perpetualTicker.ask1, -1)                
                if (amount > 10) {
                    Log("超过对冲阈值,当前总delta:", sumDelta, "买入期货")
                    m2.e.SetContractType("BTC-PERPETUAL")                    
                    m2.e.SetDirection("buy")
                    m2.e.Buy(-1, amount)
                } else {
                	hedgeMsg += ", 对冲下单量小于10"
                }
            } else {
                // delta 小于0 对冲期货做多
                var amount = _N(Math.abs(sumDelta) * perpetualTicker.bid1, -1)
                if (amount > 10) {
                    Log("超过对冲阈值,当前总delta:", sumDelta, "卖出期货")
                    m2.e.SetContractType("BTC-PERPETUAL")
                    m2.e.SetDirection("sell")
                    m2.e.Sell(-1, amount)
                } else {
                	hedgeMsg += ", 对冲下单量小于10"
                }
            }
        }

        LogStatus(_D(), "sumDelta:", sumDelta, hedgeMsg, 
        	"\n`" + JSON.stringify([m1.returnPosTbl(), m2.returnPosTbl()]) + "`", "\n`" + JSON.stringify(m2.returnTickersTbl()) + "`", "\n`" + JSON.stringify(m1.returnOptionTickersTbls()) + "`")
        Sleep(10000)
    }
}


Параметры стратегии: Deribit Option Delta Динамическая стратегия хеджирования

Адрес стратегии: https://www.fmz.com/strategy/265090

Стратегическая операция:

Deribit Option Delta Динамическая стратегия хеджирования

Deribit Option Delta Динамическая стратегия хеджирования

Эта стратегия является обучающей, в основном для обучения. Пожалуйста, используйте ее с осторожностью в реальной торговле.