{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import plotly.graph_objects as go\n", "\n", "from black_76 import *" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# 这里定价模型做了改造,兼容到期日的计算\n", "def calculate_option_pnl(\n", " s: float,\n", " k: float,\n", " r: float,\n", " t: float,\n", " v: float,\n", " cp: int,\n", " price: float\n", ") -> float:\n", " \"\"\"计算单一期权到期盈亏\"\"\"\n", " p: float = calculate_price(s, k, r, t, v, cp)\n", " return p - price" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# legs中的每个元素为字典,具体键包括k、cp、price、pos\n", "def calculate_spread_pnl(\n", " s: float,\n", " r: float,\n", " t: float,\n", " v: float,\n", " legs: list\n", ") -> float:\n", " \"\"\"计算期权价差权到期盈亏\"\"\"\n", " pnl: float = 0\n", "\n", " for leg in legs:\n", " p: float = calculate_price(s, leg[\"k\"], r, t, v, leg[\"cp\"])\n", " pnl += (p - leg[\"price\"]) * leg[\"pos\"]\n", "\n", " return pnl" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def plot_option_spread(\n", " underlying_prices: list[float],\n", " r: float,\n", " t: float,\n", " v: float,\n", " legs: list\n", "):\n", " results: dict = {}\n", "\n", " for s in underlying_prices:\n", " pnl: float = calculate_spread_pnl(s, r, t, v, legs)\n", " results[s] = pnl\n", "\n", " fig = go.Figure(data=go.Scatter(x=list(results.keys()), y=list(results.values())))\n", " fig.show()\n", "\n", " return results" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "def calculate_option_spread(\n", " underlying_prices: list[float],\n", " r: float,\n", " t: float,\n", " v: float,\n", " legs: list\n", ") -> list[float]:\n", " results: dict = {}\n", "\n", " for s in underlying_prices:\n", " pnl: float = calculate_spread_pnl(s, r, t, v, legs)\n", " results[s] = pnl\n", "\n", " return results" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "# 定价参数\n", "underlying_prices = range(2500, 3550, 50)\n", "option_strike = 3000\n", "discount_rate = 0.03\n", "expiry_time = 0 # 到期日当天\n", "pricing_volatility = 0.2\n", "option_type = 1\n", "option_price = 70" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "# 跨式价差\n", "legs = [\n", " {\n", " \"k\": 3000,\n", " \"cp\": 1,\n", " \"price\": 70,\n", " \"pos\": 1\n", " },\n", " {\n", " \"k\": 3000,\n", " \"cp\": -1,\n", " \"price\": 70,\n", " \"pos\": 1\n", " }\n", "]" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "# 牛市价差\n", "legs = [\n", " {\n", " \"k\": 3000,\n", " \"cp\": 1,\n", " \"price\": 70,\n", " \"pos\": 1\n", " },\n", " {\n", " \"k\": 3200,\n", " \"cp\": 1,\n", " \"price\": 30,\n", " \"pos\": -1\n", " }\n", "\n", "]" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "name": "days=0", "type": "scatter", "x": [ 2500, 2550, 2600, 2650, 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450, 3500 ], "y": [ 360, 310, 260, 210, 160, 110, 60, 10, -40, -90, -140, -90, -40, 10, 60, 110, 160, 210, 260, 310, 360 ] }, { "name": "days=5", "type": "scatter", "x": [ 2500, 2550, 2600, 2650, 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450, 3500 ], "y": [ 359.6875976391193, 309.71883811392695, 259.75008893805386, 209.7816171256096, 159.81779705690826, 109.90403116302281, 60.343852782409016, 12.458508722413185, -30.00264906177044, -60.234227395269016, -70.94674107228965, -59.26002829897295, -28.82109104812588, 13.228500992026738, 60.66388872905375, 109.99398881257208, 159.83551799713877, 209.7841466535558, 259.7503603004178, 309.71886081318246, 359.68759916539966 ] }, { "name": "days=10", "type": "scatter", "x": [ 2500, 2550, 2600, 2650, 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450, 3500 ], "y": [ 359.37557348148516, 309.4396049029619, 259.51335405516545, 209.63936240429734, 159.9862885899528, 111.07635540675926, 64.17847373579197, 21.71234668140545, -12.732674966866597, -35.13551031717794, -42.408349180081586, -33.639029396330564, -10.401963133571286, 24.01627731577213, 65.89180834264698, 112.0882682373388, 160.47359041617673, 209.83413908607506, 259.57901874900614, 309.4585961516884, 359.38037184990475 ] }, { "name": "days=15", "type": "scatter", "x": [ 2500, 2550, 2600, 2650, 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450, 3500 ], "y": [ 359.0722180465492, 309.19940489959043, 259.42265218402264, 209.94224355563833, 161.238776291127, 114.28085370947268, 70.70987368506252, 32.85622553753004, 3.456725630310615, -14.921248921097991, -20.55395309014314, -13.038053647753678, 6.64473818507085, 36.477476989422236, 73.98072141088448, 116.75915505038064, 162.85330134291183, 210.85999275147333, 259.88298015362994, 309.40530339022547, 359.15526081522876 ] }, { "name": "days=20", "type": "scatter", "x": [ 2500, 2550, 2600, 2650, 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450, 3500 ], "y": [ 358.81979221715136, 309.1069269390111, 259.6898177459868, 210.96021339544882, 163.64390273794538, 118.91315643396928, 78.41711706225433, 44.16497612045179, 18.24436742476017, 2.4341129696977006, -2.1665466539268436, 4.637601276851591, 22.13338393637116, 48.90046831405281, 83.13145259035313, 122.9602642849103, 166.7129935051682, 213.0444671731314, 260.969449891787, 309.8228883325279, 359.18773545879645 ] }, { "name": "days=25", "type": "scatter", "x": [ 2500, 2550, 2600, 2650, 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450, 3500 ], "y": [ 358.68681770032305, 309.2708105235133, 260.42508702672995, 212.69597596675072, 166.9475939877184, 124.39872754462797, 86.5788123478678, 55.1831439715251, 31.84296377750033, 17.863269747952735, 14.000854989693323, 20.345824136066867, 36.33549045691383, 60.88650013570718, 92.59817734926128, 129.9687423118308, 171.5758902507796, 216.19525575079257, 262.8533701776486, 310.8279650398846, 359.61530418570163 ] } ], "layout": { "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "fillpattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "autotypenumbers": "strict", "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "sequentialminus": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } } } } }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# 绘制不同剩余到期时间下的价差盈亏曲线\n", "fig = go.Figure()\n", "\n", "for days in range(0, 30, 5):\n", " t: float = days / 240\n", " results = calculate_option_spread(underlying_prices, discount_rate, t, pricing_volatility, legs)\n", " fig.add_trace(go.Scatter(x=list(results.keys()), y=list(results.values()), name=f\"days={days}\"))\n", "\n", "fig.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.2" } }, "nbformat": 4, "nbformat_minor": 4 }