Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 63 additions & 30 deletions Optiver/assignment/Basic Quoter.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,32 @@
"import time\n",
"import random\n",
"import logging\n",
"import statistics # Für rollierende Standardabweichung\n",
"\n",
"from optibook.synchronous_client import Exchange\n",
"from libs import print_positions_and_pnl, round_down_to_tick, round_up_to_tick\n",
"\n",
"from IPython.display import clear_output\n",
"\n",
"logging.getLogger('client').setLevel('ERROR')"
"logging.getLogger('client').setLevel('ERROR')\n",
"\n",
"# === Parameter für Dynamic Spread ===\n",
"ROLLING_WINDOW = 20 # Anzahl der Mid-Prices, über die Volatilität berechnet wird\n",
"VOL_MULTIPLIER = 1.5 # Faktor, um StdDev in Credit-Spreads zu übertragen\n",
"DEFAULT_VOL = 0.01 # Fallback-Volatilität, falls noch nicht genug Daten\n",
"\n",
"# === Statische Konstanten (bleiben erhalten) ===\n",
"QUOTED_VOLUME = 10\n",
"PRICE_RETREAT_PER_LOT = 0.005\n",
"POSITION_LIMIT = 100\n",
"\n",
"# === Connect to Exchange und Instruments holen ===\n",
"exchange = Exchange()\n",
"exchange.connect()\n",
"INSTRUMENTS = exchange.get_instruments()\n",
"\n",
"# === Rolling‐Mid‐Historie initialisieren ===\n",
"mid_history = [] # Liste der letzten Mid‐Preise"
]
},
{
Expand Down Expand Up @@ -123,11 +142,6 @@
"\n",
"INSTRUMENTS = exchange.get_instruments()\n",
"\n",
"QUOTED_VOLUME = 10\n",
"FIXED_MINIMUM_CREDIT = 0.15\n",
"PRICE_RETREAT_PER_LOT = 0.005\n",
"POSITION_LIMIT = 100\n",
"\n",
"while True:\n",
" print(f'')\n",
" print(f'-----------------------------------------------------------------')\n",
Expand All @@ -143,8 +157,7 @@
" # Remove all existing (still) outstanding limit orders\n",
" exchange.delete_orders(instrument.instrument_id)\n",
" \n",
" # Obtain order book and only skip this instrument if there are no bids or offers available at all on that instrument,\n",
" # as we want to decide zwischen einfachem Mid oder VWAP-basiertem Mid\n",
" # Obtain order book; skip if incomplete\n",
" instrument_order_book = exchange.get_last_price_book(instrument.instrument_id)\n",
" if not (instrument_order_book and instrument_order_book.bids and instrument_order_book.asks):\n",
" print(f'{instrument.instrument_id:>6s} -- INCOMPLETE ORDER BOOK')\n",
Expand All @@ -156,36 +169,56 @@
" # Obtain best bid and ask prices from order book (für Anzeige)\n",
" best_bid_price = instrument_order_book.bids[0].price\n",
" best_ask_price = instrument_order_book.asks[0].price\n",
" spread_ticks = round((best_ask_price - best_bid_price) / instrument.tick_size)\n",
"\n",
" # Berechne Volumina der Top-3-Level je Seite\n",
" bid_vol_top3 = sum(level.volume for level in instrument_order_book.bids[:3])\n",
" ask_vol_top3 = sum(level.volume for level in instrument_order_book.asks[:3])\n",
" use_simple_mid = False\n",
" # --- 1) Versuch Microprice Top-1, falls Spread=1 Tick und ausreichend Volumen ---\n",
" bid_size0 = instrument_order_book.bids[0].volume\n",
" ask_size0 = instrument_order_book.asks[0].volume\n",
"\n",
" if bid_vol_top3 + ask_vol_top3 > 0:\n",
" rel_diff = abs(bid_vol_top3 - ask_vol_top3) / max(bid_vol_top3, ask_vol_top3)\n",
" # Wenn sich die Top-Volumina um weniger als 10% unterscheiden, einfachen Mid verwenden\n",
" if rel_diff < 0.10:\n",
" use_simple_mid = True\n",
" if spread_ticks == 1 and (bid_size0 + ask_size0) > 0:\n",
" mid_price = (best_ask_price * bid_size0 + best_bid_price * ask_size0) / (bid_size0 + ask_size0)\n",
" else:\n",
" mid_price = None\n",
"\n",
" if use_simple_mid:\n",
" mid_price = (best_bid_price + best_ask_price) / 2.0\n",
" # --- 2) Falls Microprice nicht verwendet wurde, prüfe Top-3 VWAP vs. einfacher Mid ---\n",
" if mid_price is None:\n",
" bid_vol_top3 = sum(level.volume for level in instrument_order_book.bids[:3])\n",
" ask_vol_top3 = sum(level.volume for level in instrument_order_book.asks[:3])\n",
" total_vol3 = bid_vol_top3 + ask_vol_top3\n",
"\n",
" if total_vol3 == 0:\n",
" mid_price = (best_bid_price + best_ask_price) / 2.0\n",
" else:\n",
" rel_diff3 = abs(bid_vol_top3 - ask_vol_top3) / max(bid_vol_top3, ask_vol_top3)\n",
" if rel_diff3 < 0.10:\n",
" mid_price = (best_bid_price + best_ask_price) / 2.0\n",
" else:\n",
" mid_price = vwap_mid_from_top_levels(\n",
" instrument_order_book.bids,\n",
" instrument_order_book.asks,\n",
" depth=3\n",
" )\n",
" if mid_price is None:\n",
" mid_price = (best_bid_price + best_ask_price) / 2.0\n",
"\n",
" # --- 3) Volatilitäts‐basierter dynamic_credit (Spread) ---\n",
" mid_history.append(mid_price)\n",
" if len(mid_history) > ROLLING_WINDOW:\n",
" mid_history.pop(0)\n",
"\n",
" if len(mid_history) >= ROLLING_WINDOW:\n",
" rolling_std = statistics.pstdev(mid_history[-ROLLING_WINDOW:])\n",
" else:\n",
" mid_price = vwap_mid_from_top_levels(\n",
" instrument_order_book.bids,\n",
" instrument_order_book.asks,\n",
" depth=3\n",
" )\n",
" if mid_price is None:\n",
" print(f'{instrument.instrument_id:>6s} -- VWAP MID PRICE NOT COMPUTABLE')\n",
" continue\n",
" rolling_std = DEFAULT_VOL\n",
"\n",
" dynamic_credit = VOL_MULTIPLIER * rolling_std\n",
"\n",
" # Calculate our fair/theoretical price based on the chosen mid_price and our current position\n",
" theoretical_price = mid_price - PRICE_RETREAT_PER_LOT * position\n",
"\n",
" # Calculate final bid and ask prices to insert\n",
" bid_price = round_down_to_tick(theoretical_price - FIXED_MINIMUM_CREDIT, instrument.tick_size)\n",
" ask_price = round_up_to_tick(theoretical_price + FIXED_MINIMUM_CREDIT, instrument.tick_size)\n",
" # Calculate final bid and ask prices to insert using dynamic_credit\n",
" bid_price = round_down_to_tick(theoretical_price - dynamic_credit, instrument.tick_size)\n",
" ask_price = round_up_to_tick(theoretical_price + dynamic_credit, instrument.tick_size)\n",
" \n",
" # Calculate bid and ask volumes to insert, taking into account the exchange position_limit\n",
" max_volume_to_buy = POSITION_LIMIT - position\n",
Expand Down