Avi-L commited on
Commit
3d20945
·
verified ·
1 Parent(s): d8dfb8b

demo strategies

Browse files
Files changed (1) hide show
  1. crypto_eval/strategies.py +58 -0
crypto_eval/strategies.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Demo strategies for the crypto-quant-eval harness.
2
+
3
+ Each strategy is a function (bars, funding) -> positions: pd.Series of
4
+ units of base asset indexed by bar start time. Strategies MUST only use
5
+ information available at decision time: a bar starting at t is closed at
6
+ t+freq, so signals at t use bars shifted by 1 (the closed bar is at t-1).
7
+ The `shift_bars` helper enforces this.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import numpy as np
13
+ import pandas as pd
14
+
15
+
16
+ def shift_bars(bars: pd.DataFrame, n: int = 1) -> pd.DataFrame:
17
+ """Return bars as known at decision time t: last closed bar is t-1."""
18
+ return bars.shift(n)
19
+
20
+
21
+ def funding_carry(bars: pd.DataFrame, funding: pd.DataFrame,
22
+ threshold: float = 0.0001,
23
+ max_leverage: float = 1.0) -> pd.Series:
24
+ """Short the perp when funding is persistently positive (carry trade).
25
+
26
+ Signal: rolling 3-tick mean funding. If mean funding > threshold, hold
27
+ short notional -max_leverage; if < -threshold, hold long; else flat.
28
+ """
29
+ # funding at tick t is announced at t; a bar starting at t can use
30
+ # the tick at t-1 (announced) but not the one accruing over [t, t+8h)
31
+ # accept either a Series or a one-column DataFrame with funding_rate
32
+ if isinstance(funding, pd.DataFrame):
33
+ funding = funding["funding_rate"]
34
+ f = funding.shift(1)
35
+ signal = f.rolling(3, min_periods=1).mean()
36
+ pos = pd.Series(0.0, index=bars.index)
37
+ # expand tick-level signal to bar-level, decision at bar start t uses
38
+ # the last tick announced strictly before t
39
+ tick_signal = signal.reindex(bars.index, method="ffill")
40
+ pos[tick_signal > threshold] = -max_leverage
41
+ pos[tick_signal < -threshold] = max_leverage
42
+ return pos
43
+
44
+
45
+ def ma_crossover(bars: pd.DataFrame, funding: pd.DataFrame,
46
+ fast: int = 24, slow: int = 168) -> pd.Series:
47
+ """Classic fast/slow MA crossover on 1h close (7d slow)."""
48
+ close = shift_bars(bars)["close"]
49
+ fast_ma = close.rolling(fast).mean()
50
+ slow_ma = close.rolling(slow).mean()
51
+ pos = pd.Series(np.where(fast_ma > slow_ma, 1.0, -1.0), index=bars.index)
52
+ return pos
53
+
54
+
55
+ STRATEGIES = {
56
+ "funding_carry": funding_carry,
57
+ "ma_crossover": ma_crossover,
58
+ }