BackcastPro 0.6.2__tar.gz → 0.6.4__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.
- backcastpro-0.6.4/.claude/hand-off-download.md +59 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/.claude/settings.local.json +14 -1
- {backcastpro-0.6.2 → backcastpro-0.6.4}/.github/workflows/publish-pypi.yml +1 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/PKG-INFO +1 -1
- {backcastpro-0.6.2 → backcastpro-0.6.4}/pyproject.toml +2 -3
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/__init__.py +2 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/_broker.py +9 -2
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/backtest.py +5 -4
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/position.py +24 -1
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_backtest_api.py +2 -2
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_backtest_step_loop.py +2 -9
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_position.py +25 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/uv.lock +556 -1
- {backcastpro-0.6.2 → backcastpro-0.6.4}/.coverage +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/.gcloudignore +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/.github/workflows/docs.yml +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/.github/workflows/publish-dockerhub.yml +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/.gitignore +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/.python-version +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/.vscode/launch.json +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/.vscode/settings.json +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/AGENTS.md +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/CLAUDE.md +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/README.md +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/cloud-job/.env.example +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/cloud-job/Dockerfile +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/cloud-job/update_stocks_price.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/cloud-run/.env.example +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/cloud-run/Dockerfile +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/cloud-run/main.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/cloud-run/requirements.txt +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/docs/cloud-run-updater.md +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/docs/design-decisions.md +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/docs/developer-guide.md +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/docs/examples/SmaCross.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/docs/examples/marimo_replay.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/docs/execution-logic-report.md +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/docs/how-to-deploy-to-PyPI.md +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/docs/img/logo.drawio.svg +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/docs/index.md +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/docs/privacy.md +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/docs/troubleshooting.md +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/docs/tutorial.md +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/mkdocs.yml +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/_stats.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/api/__init__.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/api/cloud_run_client.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/api/db_manager.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/api/db_stocks_board.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/api/db_stocks_daily.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/api/db_stocks_info.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/api/stocks_board.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/api/stocks_info.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/api/stocks_price.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/order.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/BackcastPro/trade.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/__init__.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/trading_data/__init__.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/trading_data/lib/__init__.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/trading_data/lib/e_api.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/trading_data/lib/jquants.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/trading_data/lib/kabusap.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/trading_data/lib/stooq.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/trading_data/lib/util.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/trading_data/stocks_board.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/trading_data/stocks_info.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/src/trading_data/stocks_price.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/test_output.txt +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/import_equities_trades.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/import_minute_bars.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_backtest_set_data.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_cloud_run_client.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_cloud_run_main.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_db_manager.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_db_stocks_board.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_db_stocks_daily.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_db_stocks_info.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_e_api.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_j-quants.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_kabusap.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_order.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_relative_size_option_c.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_stats.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_stocks_board_wrapper.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_stocks_info_wrapper.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_stocks_price_wrapper.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_stooq.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_trade.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_update_stocks_price.py +0 -0
- {backcastpro-0.6.2 → backcastpro-0.6.4}/tests/test_util.py +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# J-Quants データダウンロード引継ぎ資料
|
|
2
|
+
|
|
3
|
+
## 目的
|
|
4
|
+
J-Quants Webサイトから2026年1月(月次分)および2月(日次分)の以下のデータを `S:\j-quants` にダウンロードする。
|
|
5
|
+
- 株価四本値 (Daily Bars)
|
|
6
|
+
- 株価分足 (Minute Bars)
|
|
7
|
+
- 株価ティック (Trades)
|
|
8
|
+
|
|
9
|
+
## 作業状況
|
|
10
|
+
- ブラウザエージェントは既に J-Quants ダッシュボードにログイン済みです。
|
|
11
|
+
- ファイルキーのパターンは特定済みですが、取得用URL(署名付きURL)は **300秒(5分)で有効期限が切れる** ため、一括でURLを取得してからダウンロードするのではなく、取得後すぐにダウンロードする必要があります。
|
|
12
|
+
|
|
13
|
+
## 対象ファイルリスト (2026年)
|
|
14
|
+
|
|
15
|
+
### 1. 2026年1月 (月次一括)
|
|
16
|
+
- `equities_bars_daily_202601.csv.gz`
|
|
17
|
+
- `equities_bars_minute_202601.csv.gz`
|
|
18
|
+
- `equities_trades_202601.csv.gz`
|
|
19
|
+
|
|
20
|
+
### 2. 2026年2月 (日次)
|
|
21
|
+
日付: 02, 03, 04, 05, 06, 09, 10, 12, 13, 16, 17, 18
|
|
22
|
+
(例: `equities_bars_daily_20260218.csv.gz`)
|
|
23
|
+
|
|
24
|
+
## URL取得方法 (ブラウザエージェントへの依頼)
|
|
25
|
+
ダッシュボードページ (`https://jpx-jquants.com/ja/dashboard/downloads/price-data/stocks`) で以下のJavaScriptを実行してURLを取得してください。
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
(async () => {
|
|
29
|
+
const key = "対象のファイルキー"; // 例: equities/bars/daily/live/equities_bars_daily_20260218.csv.gz
|
|
30
|
+
const res = await fetch('/api/trpc/bulk.bulkGet?batch=1', {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
headers: { 'Content-Type': 'application/json' },
|
|
33
|
+
body: JSON.stringify({ "0": { "json": { "key": key } } })
|
|
34
|
+
});
|
|
35
|
+
const data = await res.json();
|
|
36
|
+
return data[0]?.result?.data?.json; // 署名付きURLが返る
|
|
37
|
+
})()
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### キーの指定ルール
|
|
41
|
+
- **2026/01**: `equities/[カテゴリ]/historical/2026/equities_[名前]_202601.csv.gz`
|
|
42
|
+
- **2026/02**: `equities/[カテゴリ]/live/equities_[名前]_202602[日付].csv.gz`
|
|
43
|
+
- カテゴリ/名前の対応:
|
|
44
|
+
- 株価四本値: `bars/daily` / `bars_daily`
|
|
45
|
+
- 株価分足: `bars/minute` / `bars_minute`
|
|
46
|
+
- 株価ティック: `trades` / `trades`
|
|
47
|
+
|
|
48
|
+
## ダウンロード実行方法 (PowerShell)
|
|
49
|
+
取得したURL(`$URL`)を使って、Windowsの `curl.exe` で保存します。
|
|
50
|
+
|
|
51
|
+
```powershell
|
|
52
|
+
curl.exe -L "$URL" -o "S:\j-quants\filename.csv.gz"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 注意事項
|
|
56
|
+
- **有効期限**: URLは5分で切れます。1ファイルずつ「URL取得 -> 即座にダウンロード」のサイクルを繰り返してください。
|
|
57
|
+
- **保存先**: `S:\j-quants` 固定です。
|
|
58
|
+
- **2月のキー**: 現在(2026/02)は `live` パスにあるものが多いですが、失敗した場合は `historical/2026/02/` パスを試してください。
|
|
59
|
+
- **残存ファイル**: `S:\j-quants` に容量0のファイルや無効なXMLエラーが含まれるファイルがある場合は上書きしてください。
|
|
@@ -11,7 +11,20 @@
|
|
|
11
11
|
"Bash(git -C \"D:/Documents/marimo\" show sasa/markdown:\"frontend/src/components/editor/renderers/cell-3d-wrapper.css\")",
|
|
12
12
|
"Bash(pushd:*)",
|
|
13
13
|
"Bash(git stash:*)",
|
|
14
|
-
"Read(//c/Users/sasac/AppData/Roaming/marimo/**)"
|
|
14
|
+
"Read(//c/Users/sasac/AppData/Roaming/marimo/**)",
|
|
15
|
+
"Bash(npx:*)",
|
|
16
|
+
"Bash(where:*)",
|
|
17
|
+
"Bash(node -e \"console.log\\(require\\(''child_process''\\).execSync\\(''npx.cmd @playwright/mcp@latest --help''\\).toString\\(\\).substring\\(0, 200\\)\\)\")",
|
|
18
|
+
"Bash(npm ls:*)",
|
|
19
|
+
"Bash(npm cache:*)",
|
|
20
|
+
"Bash(npx.cmd:*)",
|
|
21
|
+
"Bash(claude mcp add:*)",
|
|
22
|
+
"Bash(CLAUDE_CODE_GIT_BASH_PATH=\"/c/Program Files/Git/bin/bash.exe\" claude mcp add --transport stdio --scope user playwright -- npx.cmd @playwright/mcp@latest)",
|
|
23
|
+
"Bash(node -e \":*)",
|
|
24
|
+
"Bash(node -e:*)",
|
|
25
|
+
"mcp__playwright__browser_navigate",
|
|
26
|
+
"mcp__playwright__browser_take_screenshot",
|
|
27
|
+
"Read(//c/Users/sasai/Downloads/logs_57994019762/**)"
|
|
15
28
|
],
|
|
16
29
|
"additionalDirectories": [
|
|
17
30
|
"d:\\Documents\\BackcastPro",
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "BackcastPro"
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.4"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="botterYosuke" },
|
|
10
10
|
]
|
|
@@ -30,7 +30,7 @@ dependencies = [
|
|
|
30
30
|
"duckdb>=0.9.0",
|
|
31
31
|
"plotly>=5.0.0",
|
|
32
32
|
"anywidget>=0.9.21",
|
|
33
|
-
"msgpack>=1.0.0"
|
|
33
|
+
"msgpack>=1.0.0"
|
|
34
34
|
]
|
|
35
35
|
|
|
36
36
|
[project.optional-dependencies]
|
|
@@ -70,4 +70,3 @@ cloud-job = [
|
|
|
70
70
|
"requests>=2.25.0",
|
|
71
71
|
"yfinance>=0.2.0",
|
|
72
72
|
]
|
|
73
|
-
|
|
@@ -11,6 +11,7 @@ BackcastPro をご利用いただきありがとうございます。
|
|
|
11
11
|
※ 使い始めはチュートリアル → 詳細はAPIリファレンスをご参照ください。
|
|
12
12
|
"""
|
|
13
13
|
from .backtest import Backtest
|
|
14
|
+
from ._broker import BankruptError
|
|
14
15
|
|
|
15
16
|
from .api.stocks_price import get_stock_daily
|
|
16
17
|
from .api.stocks_board import get_stock_board
|
|
@@ -18,6 +19,7 @@ from .api.stocks_info import get_stock_info
|
|
|
18
19
|
|
|
19
20
|
__all__ = [
|
|
20
21
|
'Backtest',
|
|
22
|
+
'BankruptError',
|
|
21
23
|
'get_stock_daily',
|
|
22
24
|
'get_stock_board',
|
|
23
25
|
'get_stock_info',
|
|
@@ -17,6 +17,11 @@ if TYPE_CHECKING:
|
|
|
17
17
|
pass
|
|
18
18
|
|
|
19
19
|
|
|
20
|
+
class BankruptError(Exception):
|
|
21
|
+
"""エクイティが0以下になった場合に発生する破産例外"""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
20
25
|
class _Broker:
|
|
21
26
|
"""
|
|
22
27
|
バックテストにおける証券取引の実行、注文管理、ポジション管理、損益計算を担当します。
|
|
@@ -199,7 +204,9 @@ class _Broker:
|
|
|
199
204
|
price = self._data[trade.code].Close.iloc[-1]
|
|
200
205
|
self._close_trade(trade, price, self._current_time)
|
|
201
206
|
self._cash = 0
|
|
202
|
-
raise
|
|
207
|
+
raise BankruptError(
|
|
208
|
+
f"エクイティが0以下になりました (equity={equity:.2f})"
|
|
209
|
+
)
|
|
203
210
|
|
|
204
211
|
def _process_orders(self):
|
|
205
212
|
data = self._data
|
|
@@ -254,7 +261,7 @@ class _Broker:
|
|
|
254
261
|
else:
|
|
255
262
|
# 成行注文(Market-if-touched / market order)
|
|
256
263
|
# 条件付き注文は常に次の始値で
|
|
257
|
-
prev_close = df.Close.iloc[-2]
|
|
264
|
+
prev_close = df.Close.iloc[-2] if len(df) >= 2 else df.Close.iloc[-1]
|
|
258
265
|
price = prev_close if self._trade_on_close and not order.is_contingent else open
|
|
259
266
|
if stop_price:
|
|
260
267
|
price = max(price, stop_price) if order.is_long else min(price, stop_price)
|
|
@@ -11,8 +11,9 @@ from typing import Callable, List, Optional, Tuple, Union
|
|
|
11
11
|
import numpy as np
|
|
12
12
|
import pandas as pd
|
|
13
13
|
|
|
14
|
-
from ._broker import _Broker
|
|
14
|
+
from ._broker import _Broker, BankruptError
|
|
15
15
|
from ._stats import compute_stats
|
|
16
|
+
from .position import Position
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class Backtest:
|
|
@@ -303,7 +304,7 @@ class Backtest:
|
|
|
303
304
|
try:
|
|
304
305
|
self._broker_instance._data = self._current_data
|
|
305
306
|
self._broker_instance.next(current_time)
|
|
306
|
-
except
|
|
307
|
+
except BankruptError:
|
|
307
308
|
self._is_finished = True
|
|
308
309
|
return False
|
|
309
310
|
|
|
@@ -456,7 +457,7 @@ class Backtest:
|
|
|
456
457
|
このプロパティは後方互換性のために残されています。
|
|
457
458
|
"""
|
|
458
459
|
if not self._is_started or self._broker_instance is None:
|
|
459
|
-
return
|
|
460
|
+
return Position._empty()
|
|
460
461
|
return self._broker_instance.position
|
|
461
462
|
|
|
462
463
|
def position_of(self, code: str) -> int:
|
|
@@ -546,7 +547,7 @@ class Backtest:
|
|
|
546
547
|
"progress": float(self.progress),
|
|
547
548
|
"equity": float(self.equity),
|
|
548
549
|
"cash": float(self.cash),
|
|
549
|
-
"position": self.position,
|
|
550
|
+
"position": self.position.size,
|
|
550
551
|
"positions": positions,
|
|
551
552
|
"closed_trades": len(self.closed_trades),
|
|
552
553
|
"step_index": self.step_index,
|
|
@@ -19,25 +19,36 @@ class Position:
|
|
|
19
19
|
... # ポジションがあります(ロングまたはショート)
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
def __init__(self, broker: '_Broker'):
|
|
22
|
+
def __init__(self, broker: '_Broker | None'):
|
|
23
23
|
self.__broker = broker
|
|
24
24
|
|
|
25
|
+
@classmethod
|
|
26
|
+
def _empty(cls) -> 'Position':
|
|
27
|
+
"""ブローカー未設定時のゼロポジションを返す。"""
|
|
28
|
+
return cls(broker=None)
|
|
29
|
+
|
|
25
30
|
def __bool__(self):
|
|
26
31
|
return self.size != 0
|
|
27
32
|
|
|
28
33
|
@property
|
|
29
34
|
def size(self) -> float:
|
|
30
35
|
"""資産単位でのポジションサイズ。ショートポジションの場合は負の値。"""
|
|
36
|
+
if self.__broker is None:
|
|
37
|
+
return 0
|
|
31
38
|
return sum(trade.size for trade in self.__broker.trades)
|
|
32
39
|
|
|
33
40
|
@property
|
|
34
41
|
def pl(self) -> float:
|
|
35
42
|
"""現在のポジションの利益(正)または損失(負)を現金単位で。"""
|
|
43
|
+
if self.__broker is None:
|
|
44
|
+
return 0
|
|
36
45
|
return sum(trade.pl for trade in self.__broker.trades)
|
|
37
46
|
|
|
38
47
|
@property
|
|
39
48
|
def pl_pct(self) -> float:
|
|
40
49
|
"""現在のポジションの利益(正)または損失(負)をパーセントで。"""
|
|
50
|
+
if self.__broker is None:
|
|
51
|
+
return 0
|
|
41
52
|
total_invested = sum(trade.entry_price * abs(trade.size) for trade in self.__broker.trades)
|
|
42
53
|
return (self.pl / total_invested) * 100 if total_invested else 0
|
|
43
54
|
|
|
@@ -51,10 +62,22 @@ class Position:
|
|
|
51
62
|
"""ポジションがショート(ポジションサイズが負)の場合True。"""
|
|
52
63
|
return self.size < 0
|
|
53
64
|
|
|
65
|
+
def to_dict(self) -> dict:
|
|
66
|
+
"""ポジション情報をシリアライズ可能な辞書として返す。"""
|
|
67
|
+
return {
|
|
68
|
+
"size": self.size,
|
|
69
|
+
"pl": self.pl,
|
|
70
|
+
"pl_pct": self.pl_pct,
|
|
71
|
+
"is_long": self.is_long,
|
|
72
|
+
"is_short": self.is_short,
|
|
73
|
+
}
|
|
74
|
+
|
|
54
75
|
def close(self, portion: float = 1.):
|
|
55
76
|
"""
|
|
56
77
|
各アクティブな取引の「一部」を決済することで、ポジションの一部を決済します。詳細は「Trade.close」を参照してください。
|
|
57
78
|
"""
|
|
79
|
+
if self.__broker is None:
|
|
80
|
+
return
|
|
58
81
|
for trade in self.__broker.trades:
|
|
59
82
|
trade.close(portion)
|
|
60
83
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"""
|
|
2
2
|
TDD Tests for BackcastPro Public API Extensions
|
|
3
3
|
|
|
4
|
-
Goal: Add public API for
|
|
4
|
+
Goal: Add public API for state access and callback mechanism.
|
|
5
5
|
|
|
6
6
|
Phase 1 Tests:
|
|
7
7
|
1. step_index property - read-only access to _step_index
|
|
8
|
-
2. get_state_snapshot() - returns current state as dict
|
|
8
|
+
2. get_state_snapshot() - returns current state as dict
|
|
9
9
|
3. add_trade_callback() - multiple callback registration for trade events
|
|
10
10
|
|
|
11
11
|
These tests follow TDD (Red-Green-Refactor):
|
|
@@ -2,16 +2,12 @@
|
|
|
2
2
|
TDD Tests for Backtest Step Loop Mechanism
|
|
3
3
|
|
|
4
4
|
Goal: Verify that the step loop mechanism works correctly for game loop integration.
|
|
5
|
-
This tests the core backtest step behavior that the marimo game loop relies on:
|
|
6
5
|
|
|
7
6
|
1. bt.step() increments _step_index correctly
|
|
8
7
|
2. bt.step() returns True while there are more steps
|
|
9
8
|
3. bt.step() returns False when finished
|
|
10
9
|
4. bt.is_finished reflects the correct state
|
|
11
10
|
5. Multiple step() calls in a loop work correctly
|
|
12
|
-
|
|
13
|
-
These tests do NOT test marimo UI parts (mo.state, mo.Thread),
|
|
14
|
-
but focus on the underlying BackcastPro logic.
|
|
15
11
|
"""
|
|
16
12
|
|
|
17
13
|
import pytest
|
|
@@ -332,7 +328,7 @@ class TestStepLoop:
|
|
|
332
328
|
|
|
333
329
|
class TestGameLoopSimulation:
|
|
334
330
|
"""
|
|
335
|
-
Simulate the
|
|
331
|
+
Simulate the game loop pattern:
|
|
336
332
|
|
|
337
333
|
def _game_loop():
|
|
338
334
|
while bt.is_finished == False:
|
|
@@ -346,7 +342,7 @@ class TestGameLoopSimulation:
|
|
|
346
342
|
|
|
347
343
|
def test_game_loop_pattern_basic(self):
|
|
348
344
|
"""
|
|
349
|
-
Test the basic game loop pattern
|
|
345
|
+
Test the basic game loop pattern.
|
|
350
346
|
"""
|
|
351
347
|
code = "TEST"
|
|
352
348
|
df = create_sample_df(10)
|
|
@@ -625,9 +621,6 @@ class TestMultipleStocksStepLoop:
|
|
|
625
621
|
class TestStrategyDataAccess:
|
|
626
622
|
"""
|
|
627
623
|
Test that strategy can access bt.data during step().
|
|
628
|
-
|
|
629
|
-
This is critical for the marimo game loop where the strategy
|
|
630
|
-
needs to read current data on each step.
|
|
631
624
|
"""
|
|
632
625
|
|
|
633
626
|
def test_strategy_can_access_data_on_first_step(self):
|
|
@@ -30,6 +30,31 @@ def _create_bt(days=30, cash=1000000):
|
|
|
30
30
|
return bt
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
class TestPositionBeforeStart:
|
|
34
|
+
"""未開始状態での Position テスト"""
|
|
35
|
+
|
|
36
|
+
def test_position_before_start_is_falsy(self):
|
|
37
|
+
"""未開始状態のポジションはFalse"""
|
|
38
|
+
bt = _create_bt()
|
|
39
|
+
assert not bt.position
|
|
40
|
+
|
|
41
|
+
def test_position_before_start_size_zero(self):
|
|
42
|
+
"""未開始状態のポジションサイズは0"""
|
|
43
|
+
bt = _create_bt()
|
|
44
|
+
assert bt.position.size == 0
|
|
45
|
+
|
|
46
|
+
def test_position_before_start_to_dict(self):
|
|
47
|
+
"""未開始状態でも to_dict() が正常に動作"""
|
|
48
|
+
bt = _create_bt()
|
|
49
|
+
d = bt.position.to_dict()
|
|
50
|
+
assert d == {"size": 0, "pl": 0, "pl_pct": 0, "is_long": False, "is_short": False}
|
|
51
|
+
|
|
52
|
+
def test_position_before_start_close_noop(self):
|
|
53
|
+
"""未開始状態での close() はエラーなし"""
|
|
54
|
+
bt = _create_bt()
|
|
55
|
+
bt.position.close() # should not raise
|
|
56
|
+
|
|
57
|
+
|
|
33
58
|
class TestPositionBool:
|
|
34
59
|
"""Position のブール値テスト"""
|
|
35
60
|
|