Skip to content

Commit

Permalink
Update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
nkaz001 committed May 10, 2023
1 parent 42ba002 commit 1a46a37
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 135 deletions.
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Key Features
Documentation
=============

See `full document here <https://hftbacktest.readthedocs.io/en/latest/>`_.
See `full document here <https://hftbacktest.readthedocs.io/>`_.

Getting started
===============
Expand Down
38 changes: 20 additions & 18 deletions docs/tutorials/GLFT Market Making Model and Grid Trading.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@
"\n",
"In this analysis, we will focus on equations (4.6) and (4.7) in [Optimal market making](https://arxiv.org/abs/1605.01862) and explore how they can be applied to real-world scenarios.\n",
"\n",
"The optimal bid quote depth, $ \\delta^{b*}_{approx} $, and ask quote depth, $ \\delta^{a*}_{approx} $, are derived from the fair price as follows:\n",
"The optimal bid quote depth, $\\delta^{b*}_{approx}$, and ask quote depth, $\\delta^{a*}_{approx}$, are derived from the fair price as follows:\n",
"\n",
"\\begin{align}\n",
"\\delta^{b*}_{approx}(q) = {1 \\over {\\xi \\Delta}}log(1 + {\\xi \\Delta \\over k}) + {{2q + \\Delta} \\over 2}\\sqrt{{{\\gamma \\sigma^2} \\over {2A\\Delta k}}(1 + {\\xi \\Delta \\over k})^{{k \\over {\\xi \\Delta}} + 1}} \\label{eq4.6}\\tag{4.6} \\\\\n",
"\\delta^{a*}_{approx}(q) = {1 \\over {\\xi \\Delta}}log(1 + {\\xi \\Delta \\over k}) - {{2q - \\Delta} \\over 2}\\sqrt{{{\\gamma \\sigma^2} \\over {2A\\Delta k}}(1 + {\\xi \\Delta \\over k})^{{k \\over {\\xi \\Delta}} + 1}} \\label{eq4.7}\\tag{4.7}\n",
"\\end{align}\n",
"\n",
"Let's introduce $ c_1 $ and $ c_2 $ and define them by extracting the volatility 𝜎 from the square root:\n",
"Let's introduce $c_1$ and $c_2$ and define them by extracting the volatility 𝜎 from the square root:\n",
"\n",
"\\begin{align}\n",
"c_1 = {1 \\over {\\xi \\Delta}}log(1 + {\\xi \\Delta \\over k}) \\\\\n",
Expand All @@ -52,7 +52,7 @@
"\\delta^{a*}_{approx}(q) = c_1 + {\\Delta \\over 2} \\sigma c_2 - q \\sigma c_2\n",
"\\end{align}\n",
"\n",
"As you can see, this consists of the half spread and skew. $ q $ represents a market maker's inventory(position).\n",
"As you can see, this consists of the half spread and skew. $q$ represents a market maker's inventory(position).\n",
"\n",
"\\begin{align}\n",
"\\text{half spread} = C_1 + {\\Delta \\over 2} \\sigma C_2 \\\\\n",
Expand Down Expand Up @@ -80,7 +80,7 @@
"source": [
"## Calculating Trading Intensity\n",
"\n",
"To determine the optimal quotes, we need to compute $ c_1 $ and $ c_2 $. In order to do that, we need to calibrate $ A $ and $ k $ of trading intensity, as well as calculate the market volatility $ \\sigma $.\n",
"To determine the optimal quotes, we need to compute $c_1$ and $c_2$. In order to do that, we need to calibrate $A$ and $k$ of trading intensity, as well as calculate the market volatility $\\sigma$.\n",
"\n",
"Trading intensity is defined as:\n",
"\n",
Expand Down Expand Up @@ -291,7 +291,7 @@
"id": "ba53dc84",
"metadata": {},
"source": [
"Calibrate $ A $ and $ k $ using linear regression, since by taking the logarithm of both sides of lambda, it becomes $ log \\lambda = -k \\delta + logA $."
"Calibrate $A$ and $k$ using linear regression, since by taking the logarithm of both sides of lambda, it becomes $log \\lambda = -k \\delta + logA$."
]
},
{
Expand Down Expand Up @@ -479,7 +479,7 @@
"id": "ce98fd83",
"metadata": {},
"source": [
"Compute $ c_1 $ and $ c_2 $ according to the equations."
"Compute $c_1$ and $c_2$ according to the equations."
]
},
{
Expand All @@ -502,7 +502,7 @@
"id": "2ced82ca",
"metadata": {},
"source": [
"In the Guéant–Lehalle–Fernandez-Tapia formula, $ \\Delta = 1 $ and $ \\xi = \\gamma $. the value of $ \\gamma $ is arbitrarily chosen."
"In the Guéant–Lehalle–Fernandez-Tapia formula, $\\Delta = 1$ and $\\xi = \\gamma$. the value of $\\gamma$ is arbitrarily chosen."
]
},
{
Expand Down Expand Up @@ -578,8 +578,10 @@
"## Implement a Market Maker using the Model\n",
"\n",
"\n",
"<div class=\"alert alert-success\">\n",
"This example is for educational purposes only and demonstrates effective strategies for high-frequency market-making schemes. All backtests are based on a 0.005% rebate, the highest market maker rebate available on Binance Futures. See <a href=\"https://www.binance.com/en/support/announcement/binance-upgrades-usd%E2%93%A2-margined-futures-liquidity-provider-program-2023-04-04-01007356e6514df3811b0c80ab8c83bf\">Binance Upgrades USDⓢ-Margined Futures Liquidity Provider Program</a> for more details.\n",
"<div class=\"alert alert-info\">\n",
" \n",
"**Note:** This example is for educational purposes only and demonstrates effective strategies for high-frequency market-making schemes. All backtests are based on a 0.005% rebate, the highest market maker rebate available on Binance Futures. See <a href=\"https://www.binance.com/en/support/announcement/binance-upgrades-usd%E2%93%A2-margined-futures-liquidity-provider-program-2023-04-04-01007356e6514df3811b0c80ab8c83bf\">Binance Upgrades USDⓢ-Margined Futures Liquidity Provider Program</a> for more details.\n",
" \n",
"</div>\n",
"\n",
"In this example, we will disregard the forecast term and assume that the fair price is equal to the mid price, as we can expect the intrinsic value to remain stable in the short term."
Expand Down Expand Up @@ -789,11 +791,11 @@
"source": [
"## Adjustment factors\n",
"\n",
"It looks like the skew is too strong, which is why the market maker is hesitant to take on the position. To alleviate the skew, you can introduce adjustment factors, $ adj_1 $ and $ adj_2 $, to the calculated half spread and skew, as follow.\n",
"It looks like the skew is too strong, which is why the market maker is hesitant to take on the position. To alleviate the skew, you can introduce adjustment factors, $adj_1$ and $adj_2$, to the calculated half spread and skew, as follow.\n",
"\n",
"$$\n",
"\\text{half spread}_{adj} = \\text{half spread} * adj_1 \\\\\n",
"\\text{skew}_{adj} = \\text{skew} * adj_2\n",
"\\text{half spread}_{adj} = \\text{half spread} \\times adj_1 \\\\\n",
"\\text{skew}_{adj} = \\text{skew} \\times adj_2\n",
"$$"
]
},
Expand Down Expand Up @@ -1001,7 +1003,7 @@
"id": "79cc93c6",
"metadata": {},
"source": [
"Improved, but even when accounting for rebates, it can only achieve breakeven at best. As shown below, both the half spread and skew move together, primarily influenced by the $ c_2 $ and the market volatility."
"Improved, but even when accounting for rebates, it can only achieve breakeven at best. As shown below, both the half spread and skew move together, primarily influenced by the $c_2$ and the market volatility."
]
},
{
Expand Down Expand Up @@ -1283,9 +1285,9 @@
" bid_price = min(round(mid_price_tick - bid_depth), hbt.best_bid_tick) * hbt.tick_size\n",
" ask_price = max(round(mid_price_tick + ask_depth), hbt.best_ask_tick) * hbt.tick_size\n",
" \n",
" order_interval = round(max(half_spread, 1)) * hbt.tick_size\n",
" bid_price = np.floor(bid_price / order_interval) * order_interval\n",
" ask_price = np.ceil(ask_price / order_interval) * order_interval\n",
" grid_interval = round(max(half_spread, 1)) * hbt.tick_size\n",
" bid_price = np.floor(bid_price / grid_interval) * grid_interval\n",
" ask_price = np.ceil(ask_price / grid_interval) * grid_interval\n",
" \n",
" #--------------------------------------------------------\n",
" # Updates quotes.\n",
Expand All @@ -1296,7 +1298,7 @@
" new_bid_orders = Dict.empty(np.int64, np.float64)\n",
" if hbt.position < max_position:\n",
" for i in range(grid_num):\n",
" bid_price -= i * order_interval\n",
" bid_price -= i * grid_interval\n",
" bid_price_tick = round(bid_price / hbt.tick_size)\n",
" \n",
" # order price in tick is used as order id.\n",
Expand All @@ -1314,7 +1316,7 @@
" new_ask_orders = Dict.empty(np.int64, np.float64)\n",
" if hbt.position > -max_position:\n",
" for i in range(grid_num):\n",
" ask_price += i * order_interval\n",
" ask_price += i * grid_interval\n",
" ask_price_tick = round(ask_price / hbt.tick_size)\n",
" \n",
" # order price in tick is used as order id.\n",
Expand Down
28 changes: 14 additions & 14 deletions docs/tutorials/Getting Started.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@
"def print_bbo(hbt):\n",
" # Iterating until hftbacktest reaches the end of data.\n",
" while hbt.run:\n",
" # Elapse 60-sec every iteration.\n",
" # Elapses 60-sec every iteration.\n",
" # Time unit is the same as data's timestamp's unit.\n",
" # timestamp of the sample data is in microseconds.\n",
" if not hbt.elapse(60 * 1e6):\n",
" # hftbacktest encounters the end of data while elapsing.\n",
" return False\n",
" \n",
" # Print the best bid and the best offer.\n",
" # Prints the best bid and the best offer.\n",
" print(\n",
" 'current_timestamp:', hbt.current_timestamp,\n",
" ', best_bid:', round(hbt.best_bid, 3),\n",
Expand Down Expand Up @@ -419,11 +419,11 @@
" if not hbt.elapse(30 * 1e6):\n",
" return False\n",
" \n",
" # Print open orders.\n",
" # Prints open orders.\n",
" print_orders(hbt)\n",
" \n",
" if not is_order_submitted:\n",
" # Submit a buy order at 100 tick below the best bid.\n",
" # Submits a buy order at 100 tick below the best bid.\n",
" order_id = 1\n",
" order_price = hbt.best_bid - 100 * hbt.tick_size\n",
" order_qty = 1\n",
Expand Down Expand Up @@ -509,7 +509,7 @@
" \n",
" print_orders(hbt)\n",
" \n",
" # Remove inactive(FILLED, CANCELED, EXPIRED) orders from hbt.orders.\n",
" # Removes inactive(FILLED, CANCELED, EXPIRED) orders from hbt.orders.\n",
" hbt.clear_inactive_orders()\n",
" \n",
" if not is_order_submitted:\n",
Expand Down Expand Up @@ -583,7 +583,7 @@
"def watch_pending(hbt):\n",
" is_order_submitted = False\n",
" while hbt.run:\n",
" # Elapse 0.01-sec every iteration.\n",
" # Elapses 0.01-sec every iteration.\n",
" if not hbt.elapse(0.01 * 1e6):\n",
" return False\n",
" \n",
Expand All @@ -599,7 +599,7 @@
" hbt.submit_buy_order(order_id, order_price, order_qty, time_in_force)\n",
" is_order_submitted = True\n",
" \n",
" # Prevent too many prints\n",
" # Prevents too many prints\n",
" if hbt.orders[order_id].status == NEW:\n",
" return False\n",
" return True"
Expand Down Expand Up @@ -761,7 +761,7 @@
" \n",
" hbt.clear_inactive_orders()\n",
" \n",
" # Print position, balance, fee, and equity\n",
" # Prints position, balance, fee, and equity\n",
" print(\n",
" 'current_timestamp:', hbt.current_timestamp,\n",
" ', position:', hbt.position,\n",
Expand Down Expand Up @@ -852,15 +852,15 @@
" \n",
" hbt.clear_inactive_orders()\n",
" \n",
" # Cancel if there is an open order\n",
" # Cancels if there is an open order\n",
" for order_id, order in hbt.orders.items():\n",
" # an order is only cancellable if order status is NEW.\n",
" # cancel request is negated if the order is already filled or filled before cancel request is processed.\n",
" if order.cancellable:\n",
" hbt.cancel(order_id)\n",
" # You can see status still NEW and see req CANCEL.\n",
" print_orders(hbt)\n",
" # cancel request also has order entry/response latencies the same as submitting.\n",
" # cancels request also has order entry/response latencies the same as submitting.\n",
" hbt.wait_order_response(order_id)\n",
" \n",
" if not is_order_submitted:\n",
Expand Down Expand Up @@ -986,7 +986,7 @@
" \n",
" if not is_order_submitted:\n",
" order_id = 1\n",
" # Set a deep price in the opposite side to take liquidity.\n",
" # Sets a deep price in the opposite side to take liquidity.\n",
" order_price = hbt.best_bid - 50 * hbt.tick_size\n",
" order_qty = 1\n",
" time_in_force = GTC\n",
Expand Down Expand Up @@ -1085,7 +1085,7 @@
" \n",
" if not is_order_submitted:\n",
" order_id = 1\n",
" # Set a deep price in the opposite side and it will be rejected by GTX.\n",
" # Sets a deep price in the opposite side and it will be rejected by GTX.\n",
" order_price = hbt.best_bid - 100 * hbt.tick_size\n",
" order_qty = 1\n",
" time_in_force = GTX\n",
Expand Down Expand Up @@ -1161,7 +1161,7 @@
" if not hbt.elapse(1 * 1e6):\n",
" return False\n",
"\n",
" # Record data points\n",
" # Records data points\n",
" local_timestamp.append(hbt.current_timestamp)\n",
" best_bid.append(hbt.best_bid)\n",
" best_ask.append(hbt.best_ask)\n",
Expand Down Expand Up @@ -1196,7 +1196,7 @@
}
],
"source": [
"# Use Numba list for njit.\n",
"# Uses Numba list for njit.\n",
"from numba.typed import List\n",
"from numba import float64\n",
"\n",
Expand Down
26 changes: 14 additions & 12 deletions docs/tutorials/High-Frequency Grid Trading.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
"source": [
"# High-Frequency Grid Trading\n",
"\n",
"<div class=\"alert alert-success\">\n",
"This example is for educational purposes only and demonstrates effective strategies for high-frequency market-making schemes. All backtests are based on a 0.005% rebate, the highest market maker rebate available on Binance Futures. See <a href=\"https://www.binance.com/en/support/announcement/binance-upgrades-usd%E2%93%A2-margined-futures-liquidity-provider-program-2023-04-04-01007356e6514df3811b0c80ab8c83bf\">Binance Upgrades USDⓢ-Margined Futures Liquidity Provider Program</a> for more details.\n",
"<div class=\"alert alert-info\">\n",
" \n",
"**Note:** This example is for educational purposes only and demonstrates effective strategies for high-frequency market-making schemes. All backtests are based on a 0.005% rebate, the highest market maker rebate available on Binance Futures. See <a href=\"https://www.binance.com/en/support/announcement/binance-upgrades-usd%E2%93%A2-margined-futures-liquidity-provider-program-2023-04-04-01007356e6514df3811b0c80ab8c83bf\">Binance Upgrades USDⓢ-Margined Futures Liquidity Provider Program</a> for more details.\n",
" \n",
"</div>"
]
},
Expand Down Expand Up @@ -40,7 +42,7 @@
"@njit\n",
"def gridtrading(hbt, stat):\n",
" max_position = 5\n",
" order_interval = hbt.tick_size * 10\n",
" grid_interval = hbt.tick_size * 10\n",
" grid_num = 20\n",
" half_spread = hbt.tick_size * 20\n",
" \n",
Expand All @@ -50,8 +52,8 @@
" hbt.clear_inactive_orders()\n",
" \n",
" mid_price = (hbt.best_bid + hbt.best_ask) / 2.0\n",
" bid_order_begin = np.floor((mid_price - half_spread) / order_interval) * order_interval\n",
" ask_order_begin = np.ceil((mid_price + half_spread) / order_interval) * order_interval\n",
" bid_order_begin = np.floor((mid_price - half_spread) / grid_interval) * grid_interval\n",
" ask_order_begin = np.ceil((mid_price + half_spread) / grid_interval) * grid_interval\n",
" \n",
" order_qty = 0.1\n",
" last_order_id = -1\n",
Expand All @@ -60,7 +62,7 @@
" new_bid_orders = Dict.empty(np.int64, np.float64)\n",
" if hbt.position < max_position:\n",
" for i in range(grid_num):\n",
" bid_order_begin -= i * order_interval\n",
" bid_order_begin -= i * grid_interval\n",
" bid_order_tick = round(bid_order_begin / hbt.tick_size)\n",
" # Do not post buy orders above the best bid.\n",
" if bid_order_tick > hbt.best_bid_tick:\n",
Expand All @@ -83,7 +85,7 @@
" new_ask_orders = Dict.empty(np.int64, np.float64)\n",
" if hbt.position > -max_position:\n",
" for i in range(grid_num):\n",
" ask_order_begin += i * order_interval\n",
" ask_order_begin += i * grid_interval\n",
" ask_order_tick = round(ask_order_begin / hbt.tick_size)\n",
" # Do not post sell orders below the best ask.\n",
" if ask_order_tick < hbt.best_ask_tick:\n",
Expand Down Expand Up @@ -241,7 +243,7 @@
"@njit\n",
"def gridtrading(hbt, stat, skew):\n",
" max_position = 5\n",
" order_interval = hbt.tick_size * 10\n",
" grid_interval = hbt.tick_size * 10\n",
" grid_num = 20\n",
" half_spread = hbt.tick_size * 20\n",
" \n",
Expand All @@ -252,8 +254,8 @@
" \n",
" mid_price = (hbt.best_bid + hbt.best_ask) / 2.0\n",
" reservation_price = mid_price - skew * hbt.position * hbt.tick_size\n",
" bid_order_begin = np.floor((reservation_price - half_spread) / order_interval) * order_interval\n",
" ask_order_begin = np.ceil((reservation_price + half_spread) / order_interval) * order_interval\n",
" bid_order_begin = np.floor((reservation_price - half_spread) / grid_interval) * grid_interval\n",
" ask_order_begin = np.ceil((reservation_price + half_spread) / grid_interval) * grid_interval\n",
" \n",
" order_qty = 0.1 # np.round(notional_order_qty / mid_price / hbt.lot_size) * hbt.lot_size\n",
" last_order_id = -1\n",
Expand All @@ -262,7 +264,7 @@
" new_bid_orders = Dict.empty(np.int64, np.float64)\n",
" if hbt.position < max_position: # hbt.position * mid_price < max_notional_position\n",
" for i in range(grid_num):\n",
" bid_order_begin -= i * order_interval\n",
" bid_order_begin -= i * grid_interval\n",
" bid_order_tick = round(bid_order_begin / hbt.tick_size)\n",
" # Do not post buy orders above the best bid.\n",
" if bid_order_tick > hbt.best_bid_tick:\n",
Expand All @@ -285,7 +287,7 @@
" new_ask_orders = Dict.empty(np.int64, np.float64)\n",
" if hbt.position > -max_position: # hbt.position * mid_price > -max_notional_position\n",
" for i in range(grid_num):\n",
" ask_order_begin += i * order_interval\n",
" ask_order_begin += i * grid_interval\n",
" ask_order_tick = round(ask_order_begin / hbt.tick_size)\n",
" # Do not post sell orders below the best ask.\n",
" if ask_order_tick < hbt.best_ask_tick:\n",
Expand Down
Loading

0 comments on commit 1a46a37

Please sign in to comment.