hawk-bt 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hawk_bt-0.1.0/PKG-INFO +252 -0
- hawk_bt-0.1.0/README.md +243 -0
- hawk_bt-0.1.0/pyproject.toml +21 -0
- hawk_bt-0.1.0/setup.cfg +4 -0
- hawk_bt-0.1.0/src/hawk_backtester/__init__.py +26 -0
- hawk_bt-0.1.0/src/hawk_backtester/hawk_engine.py +162 -0
- hawk_bt-0.1.0/src/hawk_backtester/logging.py +24 -0
- hawk_bt-0.1.0/src/hawk_backtester/runtime/__init__.py +15 -0
- hawk_bt-0.1.0/src/hawk_backtester/runtime/engine_api.py +294 -0
- hawk_bt-0.1.0/src/hawk_backtester/runtime/loop.py +362 -0
- hawk_bt-0.1.0/src/hawk_backtester/runtime/progress.py +55 -0
- hawk_bt-0.1.0/src/hawk_backtester/runtime/rust_engine_async_adapter.py +187 -0
- hawk_bt-0.1.0/src/hawk_backtester/strategy/__init__.py +13 -0
- hawk_bt-0.1.0/src/hawk_backtester/strategy/api.py +96 -0
- hawk_bt-0.1.0/src/hawk_backtester/strategy/commands.py +30 -0
- hawk_bt-0.1.0/src/hawk_bt.egg-info/PKG-INFO +252 -0
- hawk_bt-0.1.0/src/hawk_bt.egg-info/SOURCES.txt +18 -0
- hawk_bt-0.1.0/src/hawk_bt.egg-info/dependency_links.txt +1 -0
- hawk_bt-0.1.0/src/hawk_bt.egg-info/requires.txt +2 -0
- hawk_bt-0.1.0/src/hawk_bt.egg-info/top_level.txt +1 -0
hawk_bt-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hawk-bt
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client library for Hawk-Backtester — local strategy backtesting via WS <-> WASM simulator
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: numpy>=1.23
|
|
8
|
+
Requires-Dist: py-engine-rust
|
|
9
|
+
|
|
10
|
+
# py_engine — Hawk Trading Simulator Python Client
|
|
11
|
+
|
|
12
|
+
ブラウザ上の WASM トレーディングエンジンを Python から操作するクライアントライブラリ。
|
|
13
|
+
自動売買戦略の開発・バックテスト・ライブ検証に使う。
|
|
14
|
+
|
|
15
|
+
## Architecture
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Browser (WASM Engine + UI)
|
|
19
|
+
↕ WebSocket (binary, lock-step RPC)
|
|
20
|
+
py_engine (Python)
|
|
21
|
+
↕ py_engine_rust (Rust extension, required)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- **WASM エンジン**: 為替シミュレーションの本体。ブラウザ内で動作する
|
|
25
|
+
- **py_engine**: Python 側のクライアント。戦略ロジックの実行、状態管理を担当
|
|
26
|
+
- **py_engine_rust**: WS 通信・バイナリコーデック・RPC を一貫処理する Rust 実装。必須依存
|
|
27
|
+
|
|
28
|
+
## Requirements
|
|
29
|
+
|
|
30
|
+
- Python >= 3.10
|
|
31
|
+
- `py-engine-rust` (Rust extension, **必須**)
|
|
32
|
+
- `numpy >= 1.23`
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install -e .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import asyncio
|
|
42
|
+
from py_engine.runtime.rust_engine_async_adapter import RustEngineAsyncAdapter
|
|
43
|
+
from py_engine.runtime.loop import run_attached
|
|
44
|
+
from py_engine.strategy.api import Strategy, Context
|
|
45
|
+
|
|
46
|
+
class MyStrategy(Strategy):
|
|
47
|
+
async def step(self, ctx: Context) -> None:
|
|
48
|
+
s = ctx.state.statics
|
|
49
|
+
price = s.current_rate
|
|
50
|
+
|
|
51
|
+
if price > 100.0 and s.tickets_num == 0:
|
|
52
|
+
await ctx.engine.place_ticket(side="buy", units=10, sub_limit_pips=5.0, stop_order_pips=3.0)
|
|
53
|
+
|
|
54
|
+
async def main():
|
|
55
|
+
engine = RustEngineAsyncAdapter(host="127.0.0.1", port=8787)
|
|
56
|
+
await engine.start()
|
|
57
|
+
await engine.wait_connected(timeout=None)
|
|
58
|
+
|
|
59
|
+
result = await run_attached(engine, MyStrategy(), gate_policy="eager")
|
|
60
|
+
print(f"Steps: {result.steps}, Final assets: {result.final_assets()}")
|
|
61
|
+
|
|
62
|
+
asyncio.run(main())
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## What You Can Do
|
|
66
|
+
|
|
67
|
+
### 1. Strategy を書く
|
|
68
|
+
|
|
69
|
+
`Strategy` を継承して `step()` を実装するだけ。毎ステップ自動で呼ばれる。
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
class Strategy(ABC):
|
|
73
|
+
@abstractmethod
|
|
74
|
+
async def step(self, ctx: Context) -> None: ...
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`ctx` から得られるもの:
|
|
78
|
+
- `ctx.state.statics` — 現在の資産・価格・ポジション情報 (`Statics`)
|
|
79
|
+
- `ctx.engine` — エンジン操作 (`BoundEngine`)
|
|
80
|
+
- `ctx.state.done` — シミュレーション終了フラグ
|
|
81
|
+
- `ctx.user` — 自由に使える `dict`(状態保持・ログ等)
|
|
82
|
+
|
|
83
|
+
### 2. トレード操作
|
|
84
|
+
|
|
85
|
+
#### 即時エントリー (place_ticket)
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
out = await ctx.engine.place_ticket(
|
|
89
|
+
side="buy", # "buy" | "sell"
|
|
90
|
+
units=100, # ロット数
|
|
91
|
+
sub_limit_pips=5.0, # TP (利確幅、絶対価格差) ※省略可
|
|
92
|
+
stop_order_pips=3.0, # SL (損切幅、絶対価格差) ※省略可
|
|
93
|
+
trail_pips=2.0, # トレーリングストップ ※省略可
|
|
94
|
+
)
|
|
95
|
+
# out: shape (14,) — [0]=flag(チケットID), [1..4]=reward系, [5]=current_rate, ...
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### 予約注文 (place_token)
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
out = await ctx.engine.place_token(
|
|
102
|
+
side="sell", # "buy" | "sell"
|
|
103
|
+
order="limit", # "limit" | "stop"
|
|
104
|
+
price=90.0, # 発注価格
|
|
105
|
+
units=80,
|
|
106
|
+
sub_limit_pips=8.0, # TP ※省略可
|
|
107
|
+
stop_order_pips=25.0, # SL ※省略可
|
|
108
|
+
trail_pips=None, # トレーリング ※省略可
|
|
109
|
+
time_limits=240.0, # 有効時間(ステップ数) ※省略可
|
|
110
|
+
)
|
|
111
|
+
# out: shape (18,) — [0]=flag(トークンID), ...
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### 決済 (close_step)
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
events = await ctx.engine.close_step(
|
|
118
|
+
flags=[ticket_flag], # 対象チケットのflag(ID)
|
|
119
|
+
actions=[1], # 1=全決済, 2=部分決済(REDUCE)
|
|
120
|
+
ratios=[0.0], # action=2 のとき決済比率 (0.0〜1.0)
|
|
121
|
+
)
|
|
122
|
+
# events: shape (N, 5) — 決済結果
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
複数チケットの一括決済も可能(配列で渡す)。
|
|
126
|
+
|
|
127
|
+
### 3. 市場情報の取得
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
# 最新状態
|
|
131
|
+
statics = await ctx.engine.get_statics()
|
|
132
|
+
statics.assets # 資産
|
|
133
|
+
statics.virtual_assets # 含み損益込み資産
|
|
134
|
+
statics.current_rate # 現在価格
|
|
135
|
+
statics.current_step # 現在ステップ
|
|
136
|
+
statics.total_steps # 総ステップ数
|
|
137
|
+
statics.margin_ratio # 証拠金維持率
|
|
138
|
+
statics.tickets_num # オープンチケット数
|
|
139
|
+
statics.token_num # 予約注文数
|
|
140
|
+
# ...他 20 フィールド
|
|
141
|
+
|
|
142
|
+
# チケット一覧
|
|
143
|
+
tickets = await ctx.engine.get_ticket_list()
|
|
144
|
+
# shape (rows, cols) — 各行が1チケットの詳細
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 4. シミュレーション実行
|
|
148
|
+
|
|
149
|
+
#### Attached モード(ブラウザ主導)
|
|
150
|
+
|
|
151
|
+
ブラウザ側で OHLC データが投入済みの前提で、Python は戦略の実行だけを行う。
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
result = await run_attached(engine, strategy, gate_policy="eager")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### Backtest モード(Python 主導)
|
|
158
|
+
|
|
159
|
+
Python から OHLC データを送信してバックテストを実行する。
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
result = await run_backtest(engine, strategy, ohlc5, steps=5000)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`ohlc5`: `np.ndarray` shape `(N, 5)` — `[time_ms, open, close, high, low]`
|
|
166
|
+
|
|
167
|
+
#### BacktestResult
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
result.steps # 実行ステップ数
|
|
171
|
+
result.assets # np.ndarray — ステップごとの資産推移
|
|
172
|
+
result.virtual_assets # np.ndarray — 含み損益込み資産推移
|
|
173
|
+
result.price # np.ndarray — 価格推移
|
|
174
|
+
result.final_assets() # 最終資産
|
|
175
|
+
result.max_drawdown() # 最大ドローダウン (負の値)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### 5. 接続
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from py_engine.runtime.rust_engine_async_adapter import RustEngineAsyncAdapter
|
|
182
|
+
|
|
183
|
+
engine = RustEngineAsyncAdapter(host="127.0.0.1", port=8787)
|
|
184
|
+
await engine.start()
|
|
185
|
+
await engine.wait_connected()
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### 6. Gate Policy
|
|
189
|
+
|
|
190
|
+
ステップ内の整合性同期モード。ブラウザ側のUIで設定するか、`get_gate_policy_hint()` で自動取得する。
|
|
191
|
+
|
|
192
|
+
- **`eager`** (デフォルト): 毎操作で `affect` + `get_statics` を実行。正確だが遅い
|
|
193
|
+
- **`step_end`**: ステップ終了時のみ同期。高速だが中間状態は古い可能性がある
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
gate_policy = await engine.get_gate_policy_hint() or "eager"
|
|
197
|
+
result = await run_attached(engine, strategy, gate_policy=gate_policy)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Responsibility Split
|
|
201
|
+
|
|
202
|
+
### py_engine が担当すること
|
|
203
|
+
|
|
204
|
+
- WebSocket 接続管理(サーバ起動、接続待ち、切断検知)
|
|
205
|
+
- バイナリプロトコルの encode/decode(Rust 実装)
|
|
206
|
+
- RPC 通信(送信 → 応答待ち、タイムアウト、エラーハンドリング)
|
|
207
|
+
- ステップループの制御(`run_attached` / `run_backtest`)
|
|
208
|
+
- 状態の自動同期(`BoundEngine` が `affect` → `get_statics` を自動実行)
|
|
209
|
+
- 終端検出(破産 `GAME_BREAK` / 終了 `GAME_END`)
|
|
210
|
+
- 進捗表示(`create_progress_printer`)
|
|
211
|
+
|
|
212
|
+
### ユーザーが担当すること
|
|
213
|
+
|
|
214
|
+
- **戦略ロジック**: いつ・何を・どれだけ売買するかの判断
|
|
215
|
+
- **パラメータ設計**: TP/SL 幅、ロット数、エントリー条件
|
|
216
|
+
- **リスク管理**: 最大ポジション数、証拠金維持率の監視、ドローダウン制限
|
|
217
|
+
- **OHLC データの用意**: backtest モードでは `(N, 5)` の numpy 配列を自分で用意する
|
|
218
|
+
- **結果の分析**: `BacktestResult` の解釈、パフォーマンス評価
|
|
219
|
+
- **ブラウザ側の起動**: WASM エンジンを含むブラウザ UI を事前に開いておく
|
|
220
|
+
|
|
221
|
+
### py_engine がやらないこと
|
|
222
|
+
|
|
223
|
+
- 戦略の推奨や最適化
|
|
224
|
+
- リスクの自動制限(ユーザーが `step()` 内で判断する)
|
|
225
|
+
- OHLC データの取得・前処理
|
|
226
|
+
- ブラウザ側の WASM エンジン管理
|
|
227
|
+
|
|
228
|
+
## TP/SL の仕様
|
|
229
|
+
|
|
230
|
+
- TP/SL 値は**絶対価格差**(pips やパーセントではない)
|
|
231
|
+
- Buy の場合: TP ヒット = `high >= open_rate + sub_limit_pips`
|
|
232
|
+
- Buy の場合: SL ヒット = `low <= open_rate - stop_order_pips`
|
|
233
|
+
- 同一バーで TP と SL の両方がヒットした場合: **SL が優先**
|
|
234
|
+
- 決済価格はバーの close 価格(正確な TP/SL 水準ではない)
|
|
235
|
+
|
|
236
|
+
## Project Structure
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
py_engine/
|
|
240
|
+
├── src/py_engine/
|
|
241
|
+
│ ├── runtime/
|
|
242
|
+
│ │ ├── engine_api.py # Statics, BoundEngine
|
|
243
|
+
│ │ ├── loop.py # run_backtest, run_attached, BacktestResult
|
|
244
|
+
│ │ ├── rust_engine_async_adapter.py # RustEngineAsyncAdapter (エンジン本体)
|
|
245
|
+
│ │ └── progress.py # 進捗バー
|
|
246
|
+
│ ├── strategy/
|
|
247
|
+
│ │ └── api.py # Strategy, Context, EngineState, Engine protocol
|
|
248
|
+
│ └── results/ # (拡張用)
|
|
249
|
+
├── examples/
|
|
250
|
+
│ └── simple_ma.py # MA クロスオーバー戦略のサンプル
|
|
251
|
+
└── pyproject.toml
|
|
252
|
+
```
|
hawk_bt-0.1.0/README.md
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# py_engine — Hawk Trading Simulator Python Client
|
|
2
|
+
|
|
3
|
+
ブラウザ上の WASM トレーディングエンジンを Python から操作するクライアントライブラリ。
|
|
4
|
+
自動売買戦略の開発・バックテスト・ライブ検証に使う。
|
|
5
|
+
|
|
6
|
+
## Architecture
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
Browser (WASM Engine + UI)
|
|
10
|
+
↕ WebSocket (binary, lock-step RPC)
|
|
11
|
+
py_engine (Python)
|
|
12
|
+
↕ py_engine_rust (Rust extension, required)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- **WASM エンジン**: 為替シミュレーションの本体。ブラウザ内で動作する
|
|
16
|
+
- **py_engine**: Python 側のクライアント。戦略ロジックの実行、状態管理を担当
|
|
17
|
+
- **py_engine_rust**: WS 通信・バイナリコーデック・RPC を一貫処理する Rust 実装。必須依存
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- Python >= 3.10
|
|
22
|
+
- `py-engine-rust` (Rust extension, **必須**)
|
|
23
|
+
- `numpy >= 1.23`
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install -e .
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
import asyncio
|
|
33
|
+
from py_engine.runtime.rust_engine_async_adapter import RustEngineAsyncAdapter
|
|
34
|
+
from py_engine.runtime.loop import run_attached
|
|
35
|
+
from py_engine.strategy.api import Strategy, Context
|
|
36
|
+
|
|
37
|
+
class MyStrategy(Strategy):
|
|
38
|
+
async def step(self, ctx: Context) -> None:
|
|
39
|
+
s = ctx.state.statics
|
|
40
|
+
price = s.current_rate
|
|
41
|
+
|
|
42
|
+
if price > 100.0 and s.tickets_num == 0:
|
|
43
|
+
await ctx.engine.place_ticket(side="buy", units=10, sub_limit_pips=5.0, stop_order_pips=3.0)
|
|
44
|
+
|
|
45
|
+
async def main():
|
|
46
|
+
engine = RustEngineAsyncAdapter(host="127.0.0.1", port=8787)
|
|
47
|
+
await engine.start()
|
|
48
|
+
await engine.wait_connected(timeout=None)
|
|
49
|
+
|
|
50
|
+
result = await run_attached(engine, MyStrategy(), gate_policy="eager")
|
|
51
|
+
print(f"Steps: {result.steps}, Final assets: {result.final_assets()}")
|
|
52
|
+
|
|
53
|
+
asyncio.run(main())
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## What You Can Do
|
|
57
|
+
|
|
58
|
+
### 1. Strategy を書く
|
|
59
|
+
|
|
60
|
+
`Strategy` を継承して `step()` を実装するだけ。毎ステップ自動で呼ばれる。
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
class Strategy(ABC):
|
|
64
|
+
@abstractmethod
|
|
65
|
+
async def step(self, ctx: Context) -> None: ...
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`ctx` から得られるもの:
|
|
69
|
+
- `ctx.state.statics` — 現在の資産・価格・ポジション情報 (`Statics`)
|
|
70
|
+
- `ctx.engine` — エンジン操作 (`BoundEngine`)
|
|
71
|
+
- `ctx.state.done` — シミュレーション終了フラグ
|
|
72
|
+
- `ctx.user` — 自由に使える `dict`(状態保持・ログ等)
|
|
73
|
+
|
|
74
|
+
### 2. トレード操作
|
|
75
|
+
|
|
76
|
+
#### 即時エントリー (place_ticket)
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
out = await ctx.engine.place_ticket(
|
|
80
|
+
side="buy", # "buy" | "sell"
|
|
81
|
+
units=100, # ロット数
|
|
82
|
+
sub_limit_pips=5.0, # TP (利確幅、絶対価格差) ※省略可
|
|
83
|
+
stop_order_pips=3.0, # SL (損切幅、絶対価格差) ※省略可
|
|
84
|
+
trail_pips=2.0, # トレーリングストップ ※省略可
|
|
85
|
+
)
|
|
86
|
+
# out: shape (14,) — [0]=flag(チケットID), [1..4]=reward系, [5]=current_rate, ...
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### 予約注文 (place_token)
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
out = await ctx.engine.place_token(
|
|
93
|
+
side="sell", # "buy" | "sell"
|
|
94
|
+
order="limit", # "limit" | "stop"
|
|
95
|
+
price=90.0, # 発注価格
|
|
96
|
+
units=80,
|
|
97
|
+
sub_limit_pips=8.0, # TP ※省略可
|
|
98
|
+
stop_order_pips=25.0, # SL ※省略可
|
|
99
|
+
trail_pips=None, # トレーリング ※省略可
|
|
100
|
+
time_limits=240.0, # 有効時間(ステップ数) ※省略可
|
|
101
|
+
)
|
|
102
|
+
# out: shape (18,) — [0]=flag(トークンID), ...
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### 決済 (close_step)
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
events = await ctx.engine.close_step(
|
|
109
|
+
flags=[ticket_flag], # 対象チケットのflag(ID)
|
|
110
|
+
actions=[1], # 1=全決済, 2=部分決済(REDUCE)
|
|
111
|
+
ratios=[0.0], # action=2 のとき決済比率 (0.0〜1.0)
|
|
112
|
+
)
|
|
113
|
+
# events: shape (N, 5) — 決済結果
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
複数チケットの一括決済も可能(配列で渡す)。
|
|
117
|
+
|
|
118
|
+
### 3. 市場情報の取得
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
# 最新状態
|
|
122
|
+
statics = await ctx.engine.get_statics()
|
|
123
|
+
statics.assets # 資産
|
|
124
|
+
statics.virtual_assets # 含み損益込み資産
|
|
125
|
+
statics.current_rate # 現在価格
|
|
126
|
+
statics.current_step # 現在ステップ
|
|
127
|
+
statics.total_steps # 総ステップ数
|
|
128
|
+
statics.margin_ratio # 証拠金維持率
|
|
129
|
+
statics.tickets_num # オープンチケット数
|
|
130
|
+
statics.token_num # 予約注文数
|
|
131
|
+
# ...他 20 フィールド
|
|
132
|
+
|
|
133
|
+
# チケット一覧
|
|
134
|
+
tickets = await ctx.engine.get_ticket_list()
|
|
135
|
+
# shape (rows, cols) — 各行が1チケットの詳細
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 4. シミュレーション実行
|
|
139
|
+
|
|
140
|
+
#### Attached モード(ブラウザ主導)
|
|
141
|
+
|
|
142
|
+
ブラウザ側で OHLC データが投入済みの前提で、Python は戦略の実行だけを行う。
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
result = await run_attached(engine, strategy, gate_policy="eager")
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### Backtest モード(Python 主導)
|
|
149
|
+
|
|
150
|
+
Python から OHLC データを送信してバックテストを実行する。
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
result = await run_backtest(engine, strategy, ohlc5, steps=5000)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`ohlc5`: `np.ndarray` shape `(N, 5)` — `[time_ms, open, close, high, low]`
|
|
157
|
+
|
|
158
|
+
#### BacktestResult
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
result.steps # 実行ステップ数
|
|
162
|
+
result.assets # np.ndarray — ステップごとの資産推移
|
|
163
|
+
result.virtual_assets # np.ndarray — 含み損益込み資産推移
|
|
164
|
+
result.price # np.ndarray — 価格推移
|
|
165
|
+
result.final_assets() # 最終資産
|
|
166
|
+
result.max_drawdown() # 最大ドローダウン (負の値)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 5. 接続
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from py_engine.runtime.rust_engine_async_adapter import RustEngineAsyncAdapter
|
|
173
|
+
|
|
174
|
+
engine = RustEngineAsyncAdapter(host="127.0.0.1", port=8787)
|
|
175
|
+
await engine.start()
|
|
176
|
+
await engine.wait_connected()
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 6. Gate Policy
|
|
180
|
+
|
|
181
|
+
ステップ内の整合性同期モード。ブラウザ側のUIで設定するか、`get_gate_policy_hint()` で自動取得する。
|
|
182
|
+
|
|
183
|
+
- **`eager`** (デフォルト): 毎操作で `affect` + `get_statics` を実行。正確だが遅い
|
|
184
|
+
- **`step_end`**: ステップ終了時のみ同期。高速だが中間状態は古い可能性がある
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
gate_policy = await engine.get_gate_policy_hint() or "eager"
|
|
188
|
+
result = await run_attached(engine, strategy, gate_policy=gate_policy)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Responsibility Split
|
|
192
|
+
|
|
193
|
+
### py_engine が担当すること
|
|
194
|
+
|
|
195
|
+
- WebSocket 接続管理(サーバ起動、接続待ち、切断検知)
|
|
196
|
+
- バイナリプロトコルの encode/decode(Rust 実装)
|
|
197
|
+
- RPC 通信(送信 → 応答待ち、タイムアウト、エラーハンドリング)
|
|
198
|
+
- ステップループの制御(`run_attached` / `run_backtest`)
|
|
199
|
+
- 状態の自動同期(`BoundEngine` が `affect` → `get_statics` を自動実行)
|
|
200
|
+
- 終端検出(破産 `GAME_BREAK` / 終了 `GAME_END`)
|
|
201
|
+
- 進捗表示(`create_progress_printer`)
|
|
202
|
+
|
|
203
|
+
### ユーザーが担当すること
|
|
204
|
+
|
|
205
|
+
- **戦略ロジック**: いつ・何を・どれだけ売買するかの判断
|
|
206
|
+
- **パラメータ設計**: TP/SL 幅、ロット数、エントリー条件
|
|
207
|
+
- **リスク管理**: 最大ポジション数、証拠金維持率の監視、ドローダウン制限
|
|
208
|
+
- **OHLC データの用意**: backtest モードでは `(N, 5)` の numpy 配列を自分で用意する
|
|
209
|
+
- **結果の分析**: `BacktestResult` の解釈、パフォーマンス評価
|
|
210
|
+
- **ブラウザ側の起動**: WASM エンジンを含むブラウザ UI を事前に開いておく
|
|
211
|
+
|
|
212
|
+
### py_engine がやらないこと
|
|
213
|
+
|
|
214
|
+
- 戦略の推奨や最適化
|
|
215
|
+
- リスクの自動制限(ユーザーが `step()` 内で判断する)
|
|
216
|
+
- OHLC データの取得・前処理
|
|
217
|
+
- ブラウザ側の WASM エンジン管理
|
|
218
|
+
|
|
219
|
+
## TP/SL の仕様
|
|
220
|
+
|
|
221
|
+
- TP/SL 値は**絶対価格差**(pips やパーセントではない)
|
|
222
|
+
- Buy の場合: TP ヒット = `high >= open_rate + sub_limit_pips`
|
|
223
|
+
- Buy の場合: SL ヒット = `low <= open_rate - stop_order_pips`
|
|
224
|
+
- 同一バーで TP と SL の両方がヒットした場合: **SL が優先**
|
|
225
|
+
- 決済価格はバーの close 価格(正確な TP/SL 水準ではない)
|
|
226
|
+
|
|
227
|
+
## Project Structure
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
py_engine/
|
|
231
|
+
├── src/py_engine/
|
|
232
|
+
│ ├── runtime/
|
|
233
|
+
│ │ ├── engine_api.py # Statics, BoundEngine
|
|
234
|
+
│ │ ├── loop.py # run_backtest, run_attached, BacktestResult
|
|
235
|
+
│ │ ├── rust_engine_async_adapter.py # RustEngineAsyncAdapter (エンジン本体)
|
|
236
|
+
│ │ └── progress.py # 進捗バー
|
|
237
|
+
│ ├── strategy/
|
|
238
|
+
│ │ └── api.py # Strategy, Context, EngineState, Engine protocol
|
|
239
|
+
│ └── results/ # (拡張用)
|
|
240
|
+
├── examples/
|
|
241
|
+
│ └── simple_ma.py # MA クロスオーバー戦略のサンプル
|
|
242
|
+
└── pyproject.toml
|
|
243
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hawk-bt"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python client library for Hawk-Backtester — local strategy backtesting via WS <-> WASM simulator"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"numpy>=1.23",
|
|
13
|
+
"py-engine-rust",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[tool.setuptools]
|
|
17
|
+
package-dir = {"" = "src"}
|
|
18
|
+
|
|
19
|
+
[tool.setuptools.packages.find]
|
|
20
|
+
where = ["src"]
|
|
21
|
+
include = ["hawk_backtester*"]
|
hawk_bt-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""hawk_backtester -- Python backtesting engine for the Hawk trading simulator."""
|
|
2
|
+
|
|
3
|
+
from hawk_backtester.runtime.engine_api import Snapshot, Engine, EXIT_MARGIN_CALL, EXIT_COMPLETE
|
|
4
|
+
from hawk_backtester.runtime.rust_engine_async_adapter import RustEngineAsyncAdapter
|
|
5
|
+
from hawk_backtester.runtime.loop import run_backtest, run_attached, BacktestResult
|
|
6
|
+
from hawk_backtester.strategy.api import Strategy, Context, SessionState, EngineProtocol, Candles
|
|
7
|
+
from hawk_backtester.logging import configure as configure_logging
|
|
8
|
+
from hawk_backtester.hawk_engine import HawkEngine
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"HawkEngine",
|
|
12
|
+
"Snapshot",
|
|
13
|
+
"Engine",
|
|
14
|
+
"EngineProtocol",
|
|
15
|
+
"RustEngineAsyncAdapter",
|
|
16
|
+
"run_backtest",
|
|
17
|
+
"run_attached",
|
|
18
|
+
"BacktestResult",
|
|
19
|
+
"Strategy",
|
|
20
|
+
"Context",
|
|
21
|
+
"SessionState",
|
|
22
|
+
"Candles",
|
|
23
|
+
"EXIT_MARGIN_CALL",
|
|
24
|
+
"EXIT_COMPLETE",
|
|
25
|
+
"configure_logging",
|
|
26
|
+
]
|