|
@@ -16,15 +16,23 @@ if typing.TYPE_CHECKING:
|
|
|
import market
|
|
import market
|
|
|
|
|
|
|
|
def main() -> None:
|
|
def main() -> None:
|
|
|
|
|
+ weeks = int(sys.argv[1])
|
|
|
repo = dulwich.repo.Repo('../refined-prices')
|
|
repo = dulwich.repo.Repo('../refined-prices')
|
|
|
|
|
|
|
|
today = datetime.datetime.now(tz=datetime.UTC).replace(hour=0, minute=0, second=0, microsecond=0)
|
|
today = datetime.datetime.now(tz=datetime.UTC).replace(hour=0, minute=0, second=0, microsecond=0)
|
|
|
sunday = (today - datetime.timedelta(days=(today.weekday() + 1) % 7))
|
|
sunday = (today - datetime.timedelta(days=(today.weekday() + 1) % 7))
|
|
|
weekly_stats: list[MarketStats] = []
|
|
weekly_stats: list[MarketStats] = []
|
|
|
- for _ in range(52):
|
|
|
|
|
|
|
+ for _ in range(weeks):
|
|
|
weekly_stats.append(analyze_markets(prices_on_day(repo, sunday), sunday.date()))
|
|
weekly_stats.append(analyze_markets(prices_on_day(repo, sunday), sunday.date()))
|
|
|
sunday -= datetime.timedelta(days=7)
|
|
sunday -= datetime.timedelta(days=7)
|
|
|
- render_chart(list(reversed(weekly_stats)))
|
|
|
|
|
|
|
+ weekly_stats.reverse()
|
|
|
|
|
+
|
|
|
|
|
+ base = altair.Chart({'values': weekly_stats}).encode(x=altair.X('date:T', title='week'))
|
|
|
|
|
+ render_chart(base, 'ranking:Q', 'ranking', 'average IC1 rank')
|
|
|
|
|
+ print('higher is better\naverage = (0 + 3) ÷ 2 = 1.5')
|
|
|
|
|
+ render_chart(base, 'ic1_lowest:Q', '%', 'IC1 lowest')
|
|
|
|
|
+ render_chart(base, 'ic1_zero:Q', '#', 'IC1 zero trades')
|
|
|
|
|
+ render_chart(base, 'gap:Q', '%', 'trade gap')
|
|
|
|
|
|
|
|
def prices_on_day(repo: dulwich.repo.Repo, day: datetime.datetime) -> typing.Sequence[market.RawPrice]:
|
|
def prices_on_day(repo: dulwich.repo.Repo, day: datetime.datetime) -> typing.Sequence[market.RawPrice]:
|
|
|
'''refined-prices for the earliest commit on the given day'''
|
|
'''refined-prices for the earliest commit on the given day'''
|
|
@@ -37,13 +45,6 @@ def prices_on_day(repo: dulwich.repo.Repo, day: datetime.datetime) -> typing.Seq
|
|
|
_, blob = tree[b'all.json']
|
|
_, blob = tree[b'all.json']
|
|
|
return json.loads(typing.cast(dulwich.objects.Blob, repo[blob]).data.decode())
|
|
return json.loads(typing.cast(dulwich.objects.Blob, repo[blob]).data.decode())
|
|
|
|
|
|
|
|
-class MarketStats(typing.TypedDict):
|
|
|
|
|
- date: str
|
|
|
|
|
- ranking: int
|
|
|
|
|
- ic1_lowest: int
|
|
|
|
|
- markets_with_trades: int
|
|
|
|
|
- gap: float
|
|
|
|
|
-
|
|
|
|
|
def analyze_markets(prices: typing.Sequence[market.RawPrice], date: datetime.date) -> MarketStats:
|
|
def analyze_markets(prices: typing.Sequence[market.RawPrice], date: datetime.date) -> MarketStats:
|
|
|
markets: dict[str, list[market.RawPrice]] = collections.defaultdict(list)
|
|
markets: dict[str, list[market.RawPrice]] = collections.defaultdict(list)
|
|
|
for price in prices:
|
|
for price in prices:
|
|
@@ -51,10 +52,10 @@ def analyze_markets(prices: typing.Sequence[market.RawPrice], date: datetime.dat
|
|
|
continue
|
|
continue
|
|
|
markets[price['MaterialTicker']].append(price)
|
|
markets[price['MaterialTicker']].append(price)
|
|
|
|
|
|
|
|
- markets_with_trades = ranking = ic1_lowest = gap = 0
|
|
|
|
|
|
|
+ markets_with_trades = ranking = ic1_lowest = ic1_zero = gap = 0
|
|
|
for mat, mat_prices in markets.items():
|
|
for mat, mat_prices in markets.items():
|
|
|
mat_prices.sort(key=lambda p: (p['Traded7D'] or 0))
|
|
mat_prices.sort(key=lambda p: (p['Traded7D'] or 0))
|
|
|
- if mat_prices[0]['Traded7D'] == None:
|
|
|
|
|
|
|
+ if mat_prices[-1]['Traded7D'] == None:
|
|
|
continue
|
|
continue
|
|
|
markets_with_trades += 1
|
|
markets_with_trades += 1
|
|
|
for index, price in enumerate(mat_prices):
|
|
for index, price in enumerate(mat_prices):
|
|
@@ -65,33 +66,23 @@ def analyze_markets(prices: typing.Sequence[market.RawPrice], date: datetime.dat
|
|
|
ranking += index
|
|
ranking += index
|
|
|
if index == 0:
|
|
if index == 0:
|
|
|
ic1_lowest += 1
|
|
ic1_lowest += 1
|
|
|
- gap += (mat_prices[1]['Traded7D'] - mat_prices[0]['Traded7D']) / mat_prices[1]['Traded7D'] # type: ignore
|
|
|
|
|
- print(f'IC1 ranking {ranking}, lowest in {ic1_lowest} of {markets_with_trades} markets, gap {gap:.2f}')
|
|
|
|
|
|
|
+ ic1_traded = mat_prices[0]['Traded7D'] or 0
|
|
|
|
|
+ lowest_traded = mat_prices[1]['Traded7D'] or 0
|
|
|
|
|
+ if lowest_traded > 0:
|
|
|
|
|
+ if ic1_traded == 0:
|
|
|
|
|
+ ic1_zero += 1
|
|
|
|
|
+ gap += (lowest_traded - ic1_traded) / lowest_traded
|
|
|
|
|
+ print(f'{markets_with_trades} markets with trades, IC1 ranking {ranking}, lowest in {ic1_lowest}, zero in {ic1_zero}, gap {gap:.2f}')
|
|
|
return {
|
|
return {
|
|
|
'date': date.isoformat(),
|
|
'date': date.isoformat(),
|
|
|
- 'ranking': ranking,
|
|
|
|
|
- 'ic1_lowest': ic1_lowest,
|
|
|
|
|
- 'markets_with_trades': markets_with_trades,
|
|
|
|
|
- 'gap': gap,
|
|
|
|
|
|
|
+ 'ranking': ranking / markets_with_trades,
|
|
|
|
|
+ 'ic1_lowest': ic1_lowest / markets_with_trades,
|
|
|
|
|
+ 'ic1_zero': ic1_zero,
|
|
|
|
|
+ 'gap': gap / markets_with_trades,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-def render_chart(weekly_stats: typing.Sequence[MarketStats]) -> None:
|
|
|
|
|
- base = altair.Chart({'values': list(weekly_stats)}).encode(
|
|
|
|
|
- x=altair.X('date:T', title='week'),
|
|
|
|
|
- tooltip=[
|
|
|
|
|
- altair.Tooltip('date:T', title='week'),
|
|
|
|
|
- altair.Tooltip('ranking:Q', title='ranking'),
|
|
|
|
|
- altair.Tooltip('ic1_lowest:Q', title='IC1 lowest'),
|
|
|
|
|
- altair.Tooltip('markets_with_trades:Q', title='markets with trades'),
|
|
|
|
|
- altair.Tooltip('gap:Q', title='gap', format='.2f'),
|
|
|
|
|
- ],
|
|
|
|
|
- )
|
|
|
|
|
- chart = altair.vconcat(
|
|
|
|
|
- base.mark_line(point=True).encode(y=altair.Y('ranking:Q', title='sum of IC1 rank')).properties(height=160),
|
|
|
|
|
- base.mark_line(point=True).encode(y=altair.Y('ic1_lowest:Q', title='# markets where IC1 is lowest')).properties(height=160),
|
|
|
|
|
- base.mark_line(point=True).encode(y=altair.Y('gap:Q', title='trade gap')).properties(height=160),
|
|
|
|
|
- title='IC1 market stats',
|
|
|
|
|
- )
|
|
|
|
|
|
|
+def render_chart(base: altair.Chart, y: str, y_label: str, title: str) -> None:
|
|
|
|
|
+ chart = base.mark_line(point=True).encode(y=altair.Y(y, title=y_label)).properties(title=title, height=160)
|
|
|
buffer = io.BytesIO()
|
|
buffer = io.BytesIO()
|
|
|
chart.save(buffer, format='png')
|
|
chart.save(buffer, format='png')
|
|
|
display_kitty_png(buffer.getvalue())
|
|
display_kitty_png(buffer.getvalue())
|
|
@@ -110,5 +101,12 @@ def display_kitty_png(png: bytes) -> None:
|
|
|
sys.stdout.write('\n')
|
|
sys.stdout.write('\n')
|
|
|
sys.stdout.flush()
|
|
sys.stdout.flush()
|
|
|
|
|
|
|
|
|
|
+class MarketStats(typing.TypedDict):
|
|
|
|
|
+ date: str
|
|
|
|
|
+ ranking: float
|
|
|
|
|
+ ic1_lowest: float
|
|
|
|
|
+ ic1_zero: int
|
|
|
|
|
+ gap: float
|
|
|
|
|
+
|
|
|
if __name__ == '__main__':
|
|
if __name__ == '__main__':
|
|
|
main()
|
|
main()
|