auto: hourly snapshot 2026-06-07 13:34

This commit is contained in:
Scruff AI
2026-06-07 13:34:30 +07:00
parent 0f21737e05
commit 3223d4cf92
24 changed files with 46371 additions and 18 deletions
+34 -18
View File
@@ -84,15 +84,25 @@ DEFAULT_DAYS_GLOB = "20260415*"
# (the whole point of this injector)
MAP_SCALE = {
# funding_rate from HL is per-hour. Annualised bps = rate * 8760 * 10000.
# 100bps annualised → 1.0 dipole strength leg.
# Cap at ±2.0 leg strength (i.e. ±200bps annualised funding).
"funding_bps_per_strength": 100.0,
"funding_strength_cap": 2.0,
# Calibrated 2026-06-07 on 720 hourly rows from April BTC HL fundingHistory.
# Real distribution: median |val|=620bps, q90=1265bps, q99=2320bps, max=3835bps.
# 3000bps annualised → 1.0 dipole-leg strength.
# Second rebalance 2026-06-07: previous scale (1000bps/strength, cap 2.5)
# left funding firing as a near-constant DC offset at strength ~1.3 every
# minute, dominating the stress tensor. Tripling the scale shrinks each
# dipole leg to ~0.4 and lets minute-to-minute variance show through.
"funding_bps_per_strength": 3000.0,
"funding_strength_cap": 2.5,
# bs_ratio_signed ranges natively ±0.5 (since ratio is 0..1, minus 0.5).
# Scale ×2 so full ±0.5 → ±1.0 strength.
# Cap ±3.0 (rebalance 2026-06-07): single-blob encoding was mute (ρ<0.15)
# because a single density blob doesn't couple to global telemetry channels.
# Second rebalance 2026-06-07: bs_ratio is now a Y-AXIS DIPOLE (mechanically
# equivalent to funding's x-axis dipole, rotated 90°). Couples cleanly to
# stress_yy and vel_mean on equal footing with funding.
"bs_ratio_per_strength": 0.5,
"bs_ratio_strength_cap": 1.0,
"bs_ratio_strength_cap": 3.0,
# activity_excess = (trade_count / rolling_500min_mean) - 1.
# Centred at 0. -1 = zero activity. +2 = 3× baseline. +5 = 6× baseline.
@@ -115,9 +125,9 @@ EPS_BPS = 0.5 # epsilon to prevent /0 in cvd_div denominator
# Lattice spatial geometry (lattice is 1024×1024, center 512,512)
CENTER = (512.0, 512.0)
DIPOLE_OFF = 64.0 # dipole leg offset from center
OFFSET_OFF = 64.0 # velocity-bias single-blob offset from center
RING_R = 96.0 # vorticity ring radius
DIPOLE_OFF = 64.0 # dipole leg offset from center (funding x, bs_ratio y)
RING_R = 192.0 # vorticity ring radius (was 96; doubled 2026-06-07 to
# register in the global vorticity_mean metric)
SIGMA = 32.0 # gaussian sigma of each injection blob
# Vorticity ring: N legs around the ring, alternating signs to create curl.
@@ -319,8 +329,11 @@ def encode_funding_dipole(pub: zmq.Socket, funding_bps: float) -> None:
def encode_bsratio_velocity(pub: zmq.Socket, bs_ratio_signed: float) -> None:
"""bs_ratio_signed → y-axis offset blob. Positive = more buying = +y push.
Y-axis chosen to keep funding (x-dipole) and bs_ratio orthogonal."""
"""bs_ratio_signed → Y-AXIS dipole (mechanically equivalent to funding's
x-axis dipole, rotated 90°). Positive = buy pressure pushes +y leg positive,
-y leg negative. Couples to global stress_yy / vel_mean.
Second rebalance 2026-06-07: was a single offset blob that didn't couple
to any global telemetry channel."""
if not np.isfinite(bs_ratio_signed):
return
strength = bs_ratio_signed / MAP_SCALE["bs_ratio_per_strength"]
@@ -329,8 +342,8 @@ def encode_bsratio_velocity(pub: zmq.Socket, bs_ratio_signed: float) -> None:
if abs(strength) < 1e-6:
return
cx, cy = CENTER
sign = +1.0 if strength > 0 else -1.0
_send_inject(pub, cx, cy + OFFSET_OFF * sign, abs(strength))
_send_inject(pub, cx, cy - DIPOLE_OFF, -strength)
_send_inject(pub, cx, cy + DIPOLE_OFF, +strength)
def encode_activity_isotropic(pub: zmq.Socket, activity_excess: float) -> None:
@@ -458,6 +471,8 @@ def main():
help="comma-separated arm names to run (default A,T)")
ap.add_argument("--skip-funding", action="store_true",
help="don't fetch funding history (uses NaN; useful for dry run)")
ap.add_argument("--cooldown-s", type=int, default=COOLDOWN_BETWEEN_ARMS_S,
help="seconds to wait between arms (only applies after arm T)")
args = ap.parse_args()
log(f"=== market_tension_injector run_id={RUN_ID} ===")
@@ -505,7 +520,7 @@ def main():
"map_scale": MAP_SCALE,
"spatial": {
"center": list(CENTER), "dipole_off": DIPOLE_OFF,
"offset_off": OFFSET_OFF, "ring_r": RING_R,
"ring_r": RING_R,
"sigma": SIGMA, "vorticity_n_legs": VORTICITY_N_LEGS,
},
"timing": {
@@ -534,15 +549,16 @@ def main():
f"{(time.time()-tel.latest_wall)*1000 if tel.latest_wall else -1:.0f}")
try:
arms_to_run = args.arms.split(",")
arms_to_run = [a.strip().upper() for a in args.arms.split(",")]
for ai, arm in enumerate(arms_to_run):
arm = arm.strip().upper()
if arm not in ("A", "T"):
log(f"skipping unknown arm: {arm}")
continue
if ai > 0:
log(f"--- cooldown {COOLDOWN_BETWEEN_ARMS_S}s ---")
time.sleep(COOLDOWN_BETWEEN_ARMS_S)
# Only cooldown AFTER arm T (the perturbing arm).
# Arm A is passive, no field settling needed before/after it.
if ai > 0 and arms_to_run[ai - 1] == "T":
log(f"--- cooldown {args.cooldown_s}s (let field settle after arm T) ---")
time.sleep(args.cooldown_s)
arm_df = run_arm(tel, pub if arm == "T" else None, arm, df)
outf = OUT_DIR / f"arm_{arm}_{'tension' if arm=='T' else 'no_inject'}.parquet"
arm_df.to_parquet(outf)