Explorar el Código

market: analyze markets concurrently

raylu hace 2 días
padre
commit
bba1a470f3
Se han modificado 2 ficheros con 29 adiciones y 18 borrados
  1. 1 1
      cache.py
  2. 28 17
      market.py

+ 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(transport=httpx.HTTPTransport(http2=True, retries=2))
+client = httpx.Client(transport=httpx.HTTPTransport(http2=True, retries=2), timeout=10)
 
 def get(url: str, *, headers: httpx._types.HeaderTypes|None=None) -> typing.Any:
 	parsed = urllib.parse.urlparse(url)

+ 28 - 17
market.py

@@ -1,6 +1,7 @@
 from __future__ import annotations
 
 import collections
+import concurrent.futures
 import dataclasses
 import datetime
 import statistics
@@ -24,27 +25,20 @@ def main() -> None:
 	check_cxos()
 
 	markets: dict[str, list[Market]] = collections.defaultdict(list)
-	for price in raw_prices:
-		if (traded := price['AverageTraded7D']) is None or traded < 100:
-			continue
-		if price['Bid'] is None or price['Ask'] is None:
-			continue
-		if (high := price['HighYesterday']) is None or (low := price['LowYesterday']) is None:
-			continue
-		if (high - low) / high < 0.1:
-			continue
-		spread = (price['Ask'] - price['Bid']) / price['Ask']
-		if spread < 0.15:
-			continue
-		chart_analysis = analyze_price_chart(price['FullTicker'], (price['Bid'] + price['Ask']) / 2)
-		markets[price['ExchangeCode']].append(Market(price['FullTicker'], bid=price['Bid'], ask=price['Ask'],
-				spread=spread, chart_analysis=chart_analysis))
+	with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
+		futures: list[concurrent.futures.Future[Market | None]] = []
+		for price in raw_prices:
+			futures.append(executor.submit(analyze_raw_price, price))
+		for future in futures:
+			if (market := future.result()) is not None:
+				markets[market.exchange_code].append(market)
+		executor.shutdown()
 
 	print(' mat       bid   ask spread  bids filled  asks filled     profit  p75 fill time')
 	for commodities in markets.values():
 		commodities.sort(reverse=True)
 		for m in commodities:
-			print(f'{m.full_ticker:>8} {m.bid:5} {m.ask:5} {m.spread*100: 5.0f}% {m.chart_analysis.bids_filled:12.0f} '
+			print(f'{m.ticker:>4}.{m.exchange_code} {m.bid:5} {m.ask:5} {m.spread*100: 5.0f}% {m.chart_analysis.bids_filled:12.0f} '
 					f'{m.chart_analysis.asks_filled:12.0f} {m.chart_analysis.profits:10.0f}  {format_td(m.chart_analysis.p75_fill_time)}')
 		print()
 
@@ -76,6 +70,22 @@ def check_cxos() -> None:
 			print('warehouse', warehouse['LocationNaturalId'], 'is not empty')
 	print()
 
+def analyze_raw_price(price: RawPrice) -> Market | None:
+	if (traded := price['AverageTraded7D']) is None or traded < 100:
+		return
+	if price['Bid'] is None or price['Ask'] is None:
+		return
+	if (high := price['HighYesterday']) is None or (low := price['LowYesterday']) is None:
+		return
+	if (high - low) / high < 0.1:
+		return
+	spread = (price['Ask'] - price['Bid']) / price['Ask']
+	if spread < 0.15:
+		return
+	chart_analysis = analyze_price_chart(price['FullTicker'], (price['Bid'] + price['Ask']) / 2)
+	return Market(price['ExchangeCode'], price['MaterialTicker'], bid=price['Bid'], ask=price['Ask'],
+			spread=spread, chart_analysis=chart_analysis)
+
 def analyze_price_chart(exchange_ticker: str, midpoint: float) -> ChartAnalysis:
 	'''use price chart to estimate how long it takes to fill a bid and then an ask'''
 	pcpoints: list[PriceChartPoint] = [p for p in cache.get('https://rest.fnar.net/exchange/cxpc/' + exchange_ticker)
@@ -201,7 +211,8 @@ class ChartAnalysis:
 
 @dataclasses.dataclass(eq=False, frozen=True, slots=True)
 class Market:
-	full_ticker: str
+	exchange_code: str
+	ticker: str
 	bid: float
 	ask: float
 	spread: float