|
|
@@ -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()
|