Spaces:
Running
Running
File size: 5,900 Bytes
cab04ab | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | # -*- coding: utf-8 -*-
"""κΈ°μ€λΆν¬ β 'μ€λ ₯ 0μ΄μλ€λ©΄ μ΄λκΉμ§ κ°μκΉ'λ₯Ό κ³μ°νλ€.
λ κ°μ§λ₯Ό ꡬλΆνλ€.
κ°λ§ μ μΆμ μΉ (announce)
μ°Έκ°μμκ² "μ΄ μ’
λͺ©μ μ΄μΌλ‘ μ΄λ§νΌκΉμ§ λμ¨λ€"κ³ λ―Έλ¦¬ μλ €μ£Όλ κ°.
κ³Όκ±° 5λ
μ λΈλ‘ λΆνΈμ€νΈλ©ν΄μ λΈλ€. νλ©΄μ 'μ΄μ νκ³μ 'μ μ΄λ€.
μ±μ μ© κΈ°μ€ (live)
μ€μ μμλ₯Ό μ νλ κ°. μμ¦μ΄ μ§νλ λ§νΌμ **μ€μ κ²½λ‘** μμμ
μ€λ ₯ 0 μ°Έκ°μλ₯Ό λλ € λ§λ λ€. λ§€μΌ λ€μ κ³μ°νλ€.
μ λλλκ°
κΈ°μ€μ κ³Όκ±° λΆνΈμ€νΈλ©μΌλ‘ κ³ μ νλ©΄, μμ¦ μ€ κ·Έ μ’
λͺ©μ΄ ν¬κ² μ€λ₯Ό λ μ°Έκ°μ
μ μμ μ±μ μ΄ ν¨κ» λΆνλ €μ Έ μμκ° μμ₯ λ°©ν₯μ λ°λΌκ°λ€. μ¬λ°λ₯Έ λ°μ¬μ€μ
'μμ₯μ΄ μ€μ λ‘ κ·Έλ κ² μμ§μμ λ μ΄μΌλ‘ λΌ μ μμλ μ±μ 'μ΄λ€.
π κ°λ§ μ μ κ³ μ ·곡κ°νλ κ²μ μ«μκ° μλλΌ **λ°©λ²**μ΄λ€.
μ«μλ₯Ό κ³ μ νλ©΄ μμ₯μ΄ μμκ³Ό λ€λ₯΄κ² μμ§μμ λ μ±μ μ΄ ν΅μ§Έλ‘ μ΄κΈλλ€.
π κΈ°μ€ μ°Έκ°μλ μ°Έκ°μμ λκ°μ΄ μμλ£λ₯Ό λΈλ€. μ 물리면 μ°Έκ°μλ§ λΉμ©μ
μ§κ³ μμνλ€. μμλ£κ° λμ μ’
λͺ©μΌμλ‘ κ·Έ μ°¨μ΄κ° 컀μ§λ€.
"""
import os, json, warnings
import numpy as np, pandas as pd
warnings.filterwarnings("ignore")
ROOT = os.path.dirname(os.path.abspath(__file__))
BLOCK = 5
N_LIVE = 4000
N_ANNOUNCE = 20000
def _sim(returns, n, expo, fee, seed, block=None):
"""μ€λ ₯ 0 μ°Έκ°μ nλͺ
μ μ΅μ’
μμ΅λ₯ . expo λ§νΌμ μκ°μ ν¬μ§μ
μ λ
ΈμΆνλ€."""
g = np.random.default_rng(seed)
r = np.asarray(returns, dtype=float)
L = len(r)
out = np.empty(n)
for i in range(n):
if block: # λΆνΈμ€νΈλ© (κ°λ§ μ μΆμ )
nb = int(np.ceil(L / block))
st = g.integers(0, max(len(r) - block, 1), size=nb)
path = np.concatenate([r[j:j+block] for j in st])[:L]
else: # μ€μ κ²½λ‘ (μ±μ )
path = r
act = g.random(L) < expo
pos = np.where(act, g.choice([-1.0, 1.0], size=L), 0.0)
cost = np.abs(np.diff(np.r_[0.0, pos])) * fee
out[i] = np.prod(1 + np.r_[0.0, pos[:-1]] * path - cost) - 1
return np.sort(out)
def live(prices, fee, expo=2/3, n=N_LIVE, seed=None):
"""μ±μ μ© β μμ¦ κ²½κ³ΌλΆμ μ€μ κ²½λ‘ μμμ λ§λ λ€. λ§€μΌ λ€μ λΆλ₯Έλ€.
seed λ₯Ό λ μ§λ‘ μ£Όλ©΄ κ°μ λ κ°μ κ°μ΄ λμ μ¬νμ΄ λλ€.
"""
r = pd.Series(prices, dtype=float).sort_index().pct_change().fillna(0.0).values
s = seed if seed is not None else int(pd.Timestamp.utcnow().strftime("%Y%m%d"))
return _sim(r, n, expo, fee, s)
def announce(returns, fee, days, expo=2/3, n=N_ANNOUNCE, seed=20260824):
"""κ°λ§ μ μΆμ β κ³Όκ±°λ₯Ό λΈλ‘ λΆνΈμ€νΈλ©ν΄μ 'μ΄λ§νΌκΉμ§ λμ¨λ€'λ₯Ό λΈλ€."""
r = np.asarray(returns, dtype=float)
# μμ¦ κΈΈμ΄λ§νΌλ§ μ°λλ‘ μλΌ λΆμΈλ€
reps = int(np.ceil(days / len(r))) + 1
pool = np.tile(r, reps)[:max(len(r), days * 3)]
return _sim(pool[:days] if len(pool) >= days else pool, n, expo, fee, seed, block=BLOCK)
def pct_of(ret, refv):
import bisect
return bisect.bisect_left(refv, ret) / len(refv)
def score_of(ret, refv):
import math
p = min(pct_of(ret, refv), 1 - 1e-6)
return -math.log10(max(1.0 - p, 1e-6))
# βββββββββββββββββββββββ κ°λ§ 곡μ§κ° μμ± βββββββββββββββββββββββ
if __name__ == "__main__":
import seasons as S
import scoring as SC
import yfinance as yf
s1 = S.SEASONS[1]
days = (pd.Timestamp(s1["closes"]) - pd.Timestamp(s1["opens"])).days
print("μμ¦ 1 κ°λ§ 곡μ§κ° β %dμΌ Β· μμλ£ λ°μ\n" % days)
print(" %-6s %-8s %8s %11s %11s %11s"
% ("μ’
λͺ©", "λ°μ΄ν°", "μμλ£", "μ΄ μ€μ", "μ΄ μμ5%", "μ΄ μμ1%"))
out = {}
for code, a in s1["assets"].items():
src = a["src"]
if code == "BTC":
p = os.path.join(os.path.dirname(ROOT), "btc-oracle", "data", "hourly.parquet")
H = pd.read_parquet(p).sort_index()
if "close" not in H.columns:
H = H.rename(columns={"c": "close"})
px = H.close.groupby(H.index.normalize()).last()
else:
d = yf.download(src, period="5y", interval="1d",
progress=False, auto_adjust=True)["Close"]
px = (d.iloc[:, 0] if isinstance(d, pd.DataFrame) else d).dropna()
r = px.pct_change().dropna().values
fee = SC.fee_of(code)
c = announce(r, fee, days)
out[code] = {"p50": float(np.median(c)), "p95": float(np.percentile(c, 95)),
"p99": float(np.percentile(c, 99)), "fee": fee, "days": days}
print(" %-6s %-8s %7.2f%% %10.1f%% %10.1f%% %10.1f%%"
% (code, src, fee * 100, np.median(c) * 100,
np.percentile(c, 95) * 100, np.percentile(c, 99) * 100))
json.dump({"season": 1, "opens": s1["opens"], "closes": s1["closes"], "days": days,
"method": "λΈλ‘λΆνΈμ€νΈλ© 5μΌ Β· 무μμ ν¬μ§μ
Β· λ λ²λ¦¬μ§1 Β· μμλ£ λ°μ",
"note": "κ°λ§ 곡μ§μ© μΆμ μΉ. μ€μ μ±μ μ μμ¦ μ€μ κ²½λ‘λ‘ λ§€μΌ μ¬κ³μ°νλ€.",
"ceiling": out},
open(os.path.join(ROOT, "announce_ceiling.json"), "w"),
ensure_ascii=False, indent=1)
print("\n νλ©΄μ 'μ΄μ νκ³μ 'μλ μμ5%λ₯Ό μ΄λ€.")
print(" μ μ₯: finchal/announce_ceiling.json")
|