Browse Source

market: estimate bids/asks filled

raylu 2 weeks ago
parent
commit
604543ee88
3 changed files with 48 additions and 7 deletions
  1. 1 1
      cache.py
  2. 46 6
      market.py
  3. 1 0
      pyproject.toml

+ 1 - 1
cache.py

@@ -11,7 +11,7 @@ if typing.TYPE_CHECKING:
 	import httpx._types
 
 CACHE_DIR = pathlib.Path(__file__).parent / 'cache'
-client = httpx.Client()
+client = httpx.Client(transport=httpx.HTTPTransport(http2=True, retries=2))
 
 def get(url: str, *, headers: httpx._types.HeaderTypes|None=None) -> typing.Any:
 	parsed = urllib.parse.urlparse(url)

+ 46 - 6
market.py

@@ -1,12 +1,20 @@
 from __future__ import annotations
 
 import dataclasses
+import sys
 import typing
 
 import cache
 from config import config
 
 def main() -> None:
+	if len(sys.argv) > 1:
+		exchange_tickers = sys.argv[1:]
+		for ticker in exchange_tickers:
+			bids_filled, asks_filled = estimate_filled_orders(ticker, 0)
+			print(f'{ticker}: {bids_filled=}, {asks_filled=}')
+		return
+
 	check_cxos()
 
 	raw_prices: list[RawPrice] = cache.get('https://refined-prun.github.io/refined-prices/all.json')
@@ -23,12 +31,17 @@ def main() -> None:
 		spread = (price['Ask'] - price['Bid']) / price['Ask']
 		if spread < 0.15:
 			continue
-		markets.append(Market(price['FullTicker'], bid=price['Bid'], ask=price['Ask'], spread=spread, traded=traded))
-	markets.sort(key=lambda m: (m.ask - m.bid) * m.traded, reverse=True)
+		bids_filled, asks_filled = estimate_filled_orders(price['FullTicker'], (price['Bid'] + price['Ask']) / 2)
+		bid_fill_ratio = bids_filled / (bids_filled + asks_filled)
+		if bid_fill_ratio < 0.05 or bid_fill_ratio > 0.95:
+			continue
+		markets.append(Market(price['FullTicker'], bid=price['Bid'], ask=price['Ask'], spread=spread, traded=traded,
+				bids_filled=bids_filled, asks_filled=asks_filled))
+	markets.sort(key=lambda m: (m.ask - m.bid) * min(m.bids_filled, m.asks_filled), reverse=True)
 
-	print(f'{"mat":^8} {"bid":^5} {"ask":^5} spread {"traded":^7} ')
-	for market in markets:
-		print(f'{market.full_ticker:>8} {market.bid:5} {market.ask:5} {market.spread*100: 5.0f}% {market.traded:7}')
+	print(f'{"mat":^8} {"bid":^5} {"ask":^5} spread  {"traded":^7}  bids filled  asks filled')
+	for m in markets:
+		print(f'{m.full_ticker:>8} {m.bid:5} {m.ask:5} {m.spread*100: 5.0f}% {m.traded:7.0f} {m.bids_filled:10.0f} {m.asks_filled:10.0f}')
 
 def check_cxos() -> None:
 	orders: typing.Sequence[ExchangeOrder] = cache.get('https://rest.fnar.net/cxos/' + config.username,
@@ -56,6 +69,25 @@ def check_cxos() -> None:
 			print('warehouse', warehouse['LocationNaturalId'], 'is not empty')
 	print()
 
+def estimate_filled_orders(exchange_ticker: str, midpoint: float) -> tuple[float, float]:
+	'''use price chart to estimate how many bids and asks were filled'''
+	bids = asks = 0
+	for hist in cache.get('https://rest.fnar.net/exchange/cxpc/' + exchange_ticker):
+		if hist['Interval'] != 'MINUTE_FIVE':
+			continue
+		if hist['Low'] > midpoint:
+			asks += hist['Traded']
+		elif hist['High'] < midpoint:
+			bids += hist['Traded']
+		elif hist['High'] == hist['Low']:
+			assert hist['High'] == midpoint
+		else:
+			interval_bids = (hist['High'] * hist['Traded'] - hist['Volume']) / (hist['High'] - hist['Low'])
+			interval_asks = hist['Traded'] - interval_bids
+			bids += interval_bids
+			asks += interval_asks
+	return bids, asks
+
 class ExchangeOrder(typing.TypedDict):
 	MaterialTicker: str
 	ExchangeCode: str
@@ -85,6 +117,13 @@ class RawPrice(typing.TypedDict):
 	LowYesterday: float | None
 	AverageTraded7D: float | None # averaged daily traded volume over last 7 days
 
+class PriceChartPoint(typing.TypedDict):
+	Interval: typing.Literal['MINUTE_FIVE'] | typing.Literal['MINUTE_FIFTEEN'] | typing.Literal['MINUTE_THIRTY'] | typing.Literal['HOUR_ONE'] | typing.Literal['HOUR_TWO'] | typing.Literal['HOUR_FOUR'] | typing.Literal['HOUR_SIX'] | typing.Literal['HOUR_TWELVE'] | typing.Literal['DAY_ONE'] | typing.Literal['DAY_THREE']
+	High: float
+	Low: float
+	Volume: float
+	Traded: int
+
 @dataclasses.dataclass(eq=False, slots=True)
 class Market:
 	full_ticker: str
@@ -92,7 +131,8 @@ class Market:
 	ask: float
 	spread: float
 	traded: float
-
+	bids_filled: float
+	asks_filled: float
 
 if __name__ == '__main__':
 	main()

+ 1 - 0
pyproject.toml

@@ -4,6 +4,7 @@ version = '0'
 requires-python = '>=3.13'
 dependencies = [
 	'cbor2',
+	'h2',
 	'httpx',
 	'typed-argument-parser',
 ]