| """
|
| M1 (FX_PLAN.md): month-end USD flow.
|
|
|
| Two fixed windows, no parameters:
|
| END : enter at the close of the 3rd-last trading day, exit at the close of
|
| the last trading day of the month (the last 2 days)
|
| START : enter at the close of the last trading day, exit at the close of the
|
| 2nd trading day of the new month (the first 2 days)
|
| Returns are expressed as USD direction (+ = USD strengthened) so all USD pairs
|
| can be pooled; the side is the IS sign, fixed before OOS is looked at.
|
| """
|
|
|
| from __future__ import annotations
|
|
|
| import sys
|
| import numpy as np
|
|
|
| sys.path.insert(0, __file__.rsplit("\\", 1)[0] if "\\" in __file__ else ".")
|
| import fx_screen as fs # noqa: E402
|
|
|
| USD = {"EURUSD": -1, "GBPUSD": -1, "AUDUSD": -1, "NZDUSD": -1,
|
| "USDJPY": 1, "USDCHF": 1, "USDCAD": 1, "XAUUSD": -1}
|
|
|
|
|
| def windows(d):
|
| ts = d["ts"].astype("datetime64[D]")
|
| mon = ts.astype("datetime64[M]")
|
| c, cost = d["c"], d["cost"]
|
| end_r, start_r, t_end = [], [], []
|
| last = np.where(mon[1:] != mon[:-1])[0] # index of last bar of each month
|
| for i in last:
|
| if i - 2 < 0 or i + 2 >= len(c):
|
| continue
|
| end_r.append(((c[i] - c[i - 2]) - cost[i - 2]) / c[i - 2] if False else (c[i] - c[i - 2]) / c[i - 2])
|
| start_r.append((c[i + 2] - c[i]) / c[i])
|
| t_end.append(ts[i])
|
| return np.array(t_end), np.array(end_r), np.array(start_r), cost, c
|
|
|
|
|
| if __name__ == "__main__":
|
| split = np.datetime64("2016-01-01")
|
| pooled = {"END": ([], []), "START": ([], [])}
|
| print(f"{'sym':<8}{'win':>6}{'IS bp(USD+)':>12}{'IS t':>7}{'OOS bp':>9}{'OOS t':>7}")
|
| for s, usd in USD.items():
|
| d = fs.load(s, "D1")
|
| t, er, sr, cost, c = windows(d)
|
| spread = np.median(cost / c)
|
| for nm, r in (("END", er), ("START", sr)):
|
| usd_r = usd * r
|
| is_, oos = usd_r[t < split], usd_r[t >= split]
|
| pooled[nm][0].extend(is_)
|
| pooled[nm][1].extend(oos)
|
| print(f"{s:<8}{nm:>6}{is_.mean() * 1e4:>12.1f}{fs.tstat(is_):>7.2f}{oos.mean() * 1e4:>9.1f}"
|
| f"{fs.tstat(oos):>7.2f} (spread {spread * 1e4:.1f} bp)")
|
| print()
|
| for nm, (a, b) in pooled.items():
|
| side = np.sign(np.mean(a))
|
| print(f"POOLED {nm}: IS {np.mean(a) * 1e4:+.1f} bp USD (t {fs.tstat(a):.2f}) -> trade side "
|
| f"{'long USD' if side > 0 else 'short USD'}; OOS in that direction {side * np.mean(b) * 1e4:+.1f} bp "
|
| f"(t {fs.tstat(side * np.array(b)):.2f}, n {len(b)})")
|