koval-backtrader 0.9.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.
Files changed (64) hide show
  1. koval_backtrader-0.9.0/.cursor/rules/koval-backtrader.mdc +10 -0
  2. koval_backtrader-0.9.0/.github/CODEOWNERS +2 -0
  3. koval_backtrader-0.9.0/.github/ISSUE_TEMPLATE/bug_report.yml +76 -0
  4. koval_backtrader-0.9.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  5. koval_backtrader-0.9.0/.github/ISSUE_TEMPLATE/feature_request.yml +44 -0
  6. koval_backtrader-0.9.0/.github/PULL_REQUEST_TEMPLATE.md +22 -0
  7. koval_backtrader-0.9.0/.github/copilot-instructions.md +6 -0
  8. koval_backtrader-0.9.0/.github/dependabot.yml +10 -0
  9. koval_backtrader-0.9.0/.github/workflows/ci.yml +57 -0
  10. koval_backtrader-0.9.0/.github/workflows/mirror.yml +31 -0
  11. koval_backtrader-0.9.0/.github/workflows/release.yml +115 -0
  12. koval_backtrader-0.9.0/.github/workflows/scorecard.yml +31 -0
  13. koval_backtrader-0.9.0/.gitignore +17 -0
  14. koval_backtrader-0.9.0/AGENTS.md +115 -0
  15. koval_backtrader-0.9.0/CHANGELOG.md +37 -0
  16. koval_backtrader-0.9.0/CLAUDE.md +9 -0
  17. koval_backtrader-0.9.0/CODE_OF_CONDUCT.md +132 -0
  18. koval_backtrader-0.9.0/CONTRIBUTING.md +90 -0
  19. koval_backtrader-0.9.0/GEMINI.md +6 -0
  20. koval_backtrader-0.9.0/LICENSE +674 -0
  21. koval_backtrader-0.9.0/MANIFEST.in +15 -0
  22. koval_backtrader-0.9.0/PKG-INFO +140 -0
  23. koval_backtrader-0.9.0/README.md +105 -0
  24. koval_backtrader-0.9.0/SECURITY.md +44 -0
  25. koval_backtrader-0.9.0/agents_docs/README.md +39 -0
  26. koval_backtrader-0.9.0/agents_docs/agent_workflow.md +52 -0
  27. koval_backtrader-0.9.0/agents_docs/architecture.md +103 -0
  28. koval_backtrader-0.9.0/agents_docs/invariants.md +74 -0
  29. koval_backtrader-0.9.0/agents_docs/release_process.md +43 -0
  30. koval_backtrader-0.9.0/agents_docs/testing.md +57 -0
  31. koval_backtrader-0.9.0/agents_docs/troubleshooting.md +38 -0
  32. koval_backtrader-0.9.0/examples/run_backtest.py +38 -0
  33. koval_backtrader-0.9.0/pyproject.toml +75 -0
  34. koval_backtrader-0.9.0/scripts/verify.sh +14 -0
  35. koval_backtrader-0.9.0/setup.cfg +4 -0
  36. koval_backtrader-0.9.0/src/koval_backtrader/__init__.py +22 -0
  37. koval_backtrader-0.9.0/src/koval_backtrader/backtest_runner.py +116 -0
  38. koval_backtrader-0.9.0/src/koval_backtrader/bt_adapter.py +446 -0
  39. koval_backtrader-0.9.0/src/koval_backtrader/bt_analyzers.py +111 -0
  40. koval_backtrader-0.9.0/src/koval_backtrader/oco_patch.py +148 -0
  41. koval_backtrader-0.9.0/src/koval_backtrader/py.typed +0 -0
  42. koval_backtrader-0.9.0/src/koval_backtrader.egg-info/PKG-INFO +140 -0
  43. koval_backtrader-0.9.0/src/koval_backtrader.egg-info/SOURCES.txt +62 -0
  44. koval_backtrader-0.9.0/src/koval_backtrader.egg-info/dependency_links.txt +1 -0
  45. koval_backtrader-0.9.0/src/koval_backtrader.egg-info/entry_points.txt +2 -0
  46. koval_backtrader-0.9.0/src/koval_backtrader.egg-info/requires.txt +12 -0
  47. koval_backtrader-0.9.0/src/koval_backtrader.egg-info/top_level.txt +1 -0
  48. koval_backtrader-0.9.0/tests/test_agents_docs.py +98 -0
  49. koval_backtrader-0.9.0/tests/test_backtest_runner.py +106 -0
  50. koval_backtrader-0.9.0/tests/test_block_assembler_integration.py +78 -0
  51. koval_backtrader-0.9.0/tests/test_bt_adapter.py +361 -0
  52. koval_backtrader-0.9.0/tests/test_bt_adapter_htf.py +67 -0
  53. koval_backtrader-0.9.0/tests/test_bt_analyzers.py +101 -0
  54. koval_backtrader-0.9.0/tests/test_entry_point.py +84 -0
  55. koval_backtrader-0.9.0/tests/test_examples.py +71 -0
  56. koval_backtrader-0.9.0/tests/test_license_headers.py +50 -0
  57. koval_backtrader-0.9.0/tests/test_oco_patch.py +98 -0
  58. koval_backtrader-0.9.0/tests/test_package_metadata.py +89 -0
  59. koval_backtrader-0.9.0/tests/test_public_language.py +125 -0
  60. koval_backtrader-0.9.0/tests/test_public_surface.py +99 -0
  61. koval_backtrader-0.9.0/tests/test_release_workflow.py +106 -0
  62. koval_backtrader-0.9.0/tests/test_sdist_contents.py +118 -0
  63. koval_backtrader-0.9.0/tests/test_state_injection_arrays.py +100 -0
  64. koval_backtrader-0.9.0/tests/test_version.py +21 -0
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: koval-backtrader project context — always read AGENTS.md first
3
+ alwaysApply: true
4
+ ---
5
+
6
+ All project context lives in AGENTS.md at the repository root. Read it
7
+ before making changes. The definition of done is `./scripts/verify.sh`
8
+ exiting 0. Hard rules: GPL SPDX header on every source file, never import
9
+ application code, never claim the `koval` import namespace, no real-money
10
+ code path, never run git write commands.
@@ -0,0 +1,2 @@
1
+ # Default owner for everything in this repository.
2
+ * @rostredko
@@ -0,0 +1,76 @@
1
+ name: Bug report
2
+ description: Something behaves differently from what the documentation or the code says it should.
3
+ labels: ["bug"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Do not report security vulnerabilities here. See [SECURITY.md](https://github.com/koval-finance/koval-backtrader/blob/main/SECURITY.md) for private reporting.
9
+
10
+ If `load_backtest_engine()` cannot find this package, reinstall it first (`pip install -e ".[dev]"` or `pip install --force-reinstall koval-backtrader`) — entry points come from installed metadata, which an older install can leave stale.
11
+
12
+ - type: textarea
13
+ id: what-happened
14
+ attributes:
15
+ label: What happened
16
+ description: What did you observe? Paste the full error, or the incorrect trades, metrics, or equity curve.
17
+ validations:
18
+ required: true
19
+
20
+ - type: textarea
21
+ id: reproduction
22
+ attributes:
23
+ label: How to reproduce
24
+ description: The exact CLI command or Python snippet, plus the strategy graph JSON and the candles involved. A reproduction that runs against koval-engine's bundled example data is ideal.
25
+ render: shell
26
+ validations:
27
+ required: true
28
+
29
+ - type: textarea
30
+ id: expected
31
+ attributes:
32
+ label: What you expected instead
33
+ validations:
34
+ required: true
35
+
36
+ - type: input
37
+ id: adapter-version
38
+ attributes:
39
+ label: koval-backtrader version
40
+ placeholder: "0.9.0"
41
+ validations:
42
+ required: true
43
+
44
+ - type: input
45
+ id: engine-version
46
+ attributes:
47
+ label: koval-engine version
48
+ description: Output of `koval --version`.
49
+ placeholder: "0.9.0"
50
+ validations:
51
+ required: true
52
+
53
+ - type: input
54
+ id: backtrader-version
55
+ attributes:
56
+ label: backtrader version
57
+ description: Output of `pip show backtrader | grep Version`.
58
+ placeholder: "1.9.78.123"
59
+ validations:
60
+ required: true
61
+
62
+ - type: input
63
+ id: python-version
64
+ attributes:
65
+ label: Python version
66
+ placeholder: "3.12.4"
67
+ validations:
68
+ required: true
69
+
70
+ - type: input
71
+ id: os
72
+ attributes:
73
+ label: Operating system
74
+ placeholder: "macOS 15.2 / Ubuntu 24.04"
75
+ validations:
76
+ required: true
@@ -0,0 +1,8 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Report a security vulnerability
4
+ url: https://github.com/koval-finance/koval-backtrader/security/advisories/new
5
+ about: Report privately through GitHub. Never open a public issue for a security problem.
6
+ - name: Strategy, block, or metric behaviour
7
+ url: https://github.com/koval-finance/koval-engine/issues
8
+ about: Blocks, graph semantics, and metric definitions live in koval-engine. File there so every backtest engine benefits.
@@ -0,0 +1,44 @@
1
+ name: Feature request
2
+ description: Suggest a capability this backtest engine does not have.
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Please open an issue before writing a large patch, so effort is not spent on an approach that will not be merged.
9
+
10
+ Two things are permanently out of scope. **Real-money trading:** this package replays historical candles through a simulated broker and will never open a venue connection. **Strategy logic:** blocks, graph semantics, and metric definitions belong to [koval-engine](https://github.com/koval-finance/koval-engine) — file those there, so every backtest engine benefits.
11
+
12
+ Execution modelling is fees-only today. Slippage, funding, and partial fills are in scope for this repository and are the changes most likely to be accepted.
13
+
14
+ - type: textarea
15
+ id: problem
16
+ attributes:
17
+ label: The problem
18
+ description: What are you trying to do that this package makes difficult or impossible? Describe the situation, not the solution.
19
+ validations:
20
+ required: true
21
+
22
+ - type: textarea
23
+ id: solution
24
+ attributes:
25
+ label: Proposed solution
26
+ description: What you think should change. If it would change the shape of `BacktestResult`, the events emitted during a run, or anything else a consumer can observe, say so explicitly.
27
+ validations:
28
+ required: true
29
+
30
+ - type: textarea
31
+ id: alternatives
32
+ attributes:
33
+ label: Alternatives considered
34
+ description: What you tried, or why writing a separate backtest engine plugin does not solve it.
35
+ validations:
36
+ required: false
37
+
38
+ - type: checkboxes
39
+ id: dependencies
40
+ attributes:
41
+ label: Dependencies
42
+ options:
43
+ - label: This would not require a new runtime dependency, or I have explained below why one is unavoidable.
44
+ required: false
@@ -0,0 +1,22 @@
1
+ ## What this changes
2
+
3
+ <!-- One or two sentences. If it fixes an issue, write "Fixes #123". -->
4
+
5
+ ## Why
6
+
7
+ <!-- The problem this solves. Skip if the linked issue already explains it. -->
8
+
9
+ ## Checklist
10
+
11
+ - [ ] Tests added or updated, and they failed before the change
12
+ - [ ] `./scripts/verify.sh` exits 0
13
+ - [ ] Every commit is signed off (`git commit -s`) — CI enforces this
14
+ - [ ] No new runtime dependency (or the reason for one is explained above)
15
+ - [ ] Every new source file carries the GPL SPDX header
16
+ - [ ] Nothing imports application code, and no `src/koval/` was created
17
+ - [ ] If Backtrader was upgraded: the full suite was run and the OCO patch reviewed
18
+ - [ ] `CHANGELOG.md` updated under `[Unreleased]`, if this is user-visible
19
+
20
+ ## Notes for the reviewer
21
+
22
+ <!-- Anything you are unsure about, or a decision worth a second opinion. Optional. -->
@@ -0,0 +1,6 @@
1
+ All project context for this repository lives in [AGENTS.md](../AGENTS.md).
2
+ Read it before making changes. The definition of done is
3
+ `./scripts/verify.sh` exiting 0. Hard rules: GPL SPDX header on every source
4
+ file, never import application code, never claim the `koval` import
5
+ namespace, no real-money code path, and never run git write commands —
6
+ suggest, do not commit.
@@ -0,0 +1,10 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: pip
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
7
+ - package-ecosystem: github-actions
8
+ directory: "/"
9
+ schedule:
10
+ interval: weekly
@@ -0,0 +1,57 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ test:
17
+ runs-on: ubuntu-latest
18
+ strategy:
19
+ fail-fast: false
20
+ matrix:
21
+ python-version: ["3.11", "3.12", "3.13"]
22
+ steps:
23
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
24
+ with:
25
+ persist-credentials: false
26
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
27
+ with:
28
+ python-version: ${{ matrix.python-version }}
29
+ - run: python -m pip install -e ".[dev]"
30
+ # verify.sh runs ruff, the format check, and the full suite — the same
31
+ # gates as the release workflow, pinned to it by
32
+ # tests/test_agents_docs.py. The entry-point, licence-header,
33
+ # packaging, public-surface, and public-language guards are pytest
34
+ # tests and run inside it.
35
+ - run: ./scripts/verify.sh
36
+
37
+ dco:
38
+ runs-on: ubuntu-latest
39
+ if: github.event_name == 'pull_request'
40
+ steps:
41
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
42
+ with:
43
+ fetch-depth: 0
44
+ persist-credentials: false
45
+ - name: Require Signed-off-by on every commit
46
+ env:
47
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
48
+ HEAD_SHA: ${{ github.event.pull_request.head.sha }}
49
+ run: |
50
+ missing=$(git log --format='%H %s' --invert-grep --grep='^Signed-off-by: ' "$BASE_SHA..$HEAD_SHA")
51
+ if [ -n "$missing" ]; then
52
+ echo "Commits missing a DCO sign-off:"
53
+ echo "$missing"
54
+ echo "Fix with: git commit --amend -s (or git rebase --signoff main)"
55
+ exit 1
56
+ fi
57
+ echo "All commits are signed off."
@@ -0,0 +1,31 @@
1
+ name: Mirror to GitLab
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ["v*"]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ mirror:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
16
+ with:
17
+ fetch-depth: 0
18
+ persist-credentials: false
19
+ - name: Push to GitLab
20
+ env:
21
+ GITLAB_TOKEN: ${{ secrets.GITLAB_MIRROR_TOKEN }}
22
+ run: |
23
+ # The mirror is a convenience, not infrastructure. When the token is
24
+ # not configured, skip quietly rather than failing every push to main.
25
+ if [ -z "$GITLAB_TOKEN" ]; then
26
+ echo "GITLAB_MIRROR_TOKEN is not set; skipping the mirror."
27
+ exit 0
28
+ fi
29
+ git remote add gitlab \
30
+ "https://oauth2:${GITLAB_TOKEN}@gitlab.com/koval-group/koval-backtrader.git"
31
+ git push gitlab refs/remotes/origin/main:refs/heads/main --tags
@@ -0,0 +1,115 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ verify:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ["3.11", "3.12", "3.13"]
17
+ steps:
18
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
+ with:
20
+ persist-credentials: false
21
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+ - name: Install development dependencies
25
+ run: python -m pip install -e ".[dev]"
26
+ - name: Lint
27
+ run: ruff check .
28
+ - name: Check formatting
29
+ run: ruff format --check .
30
+ - name: Test
31
+ run: pytest -q
32
+
33
+ build:
34
+ needs: verify
35
+ runs-on: ubuntu-latest
36
+ steps:
37
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
38
+ with:
39
+ persist-credentials: false
40
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
41
+ with:
42
+ python-version: "3.11"
43
+ - name: Verify the tag matches the packaged version
44
+ run: |
45
+ tag="${GITHUB_REF_NAME#v}"
46
+ version=$(python -c "import tomllib,pathlib;print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])")
47
+ if [ "$tag" != "$version" ]; then
48
+ echo "Tag $GITHUB_REF_NAME does not match pyproject version $version"
49
+ exit 1
50
+ fi
51
+ - name: Extract and validate the changelog entry
52
+ run: |
53
+ version="${GITHUB_REF_NAME#v}"
54
+ awk -v v="$version" '
55
+ $0 ~ "^## \\[" v "\\]" { found=1; next }
56
+ found && /^## \[/ { exit }
57
+ found { print }
58
+ ' CHANGELOG.md > release-notes.md
59
+ if ! grep -q '[^[:space:]]' release-notes.md; then
60
+ echo "No changelog entry found for $version"
61
+ exit 1
62
+ fi
63
+ - name: Install build tooling
64
+ run: python -m pip install build twine
65
+ - name: Build distributions
66
+ run: python -m build
67
+ - name: Validate distributions
68
+ run: twine check --strict dist/*
69
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
70
+ with:
71
+ name: dist
72
+ path: dist/
73
+ if-no-files-found: error
74
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
75
+ with:
76
+ name: release-notes
77
+ path: release-notes.md
78
+ if-no-files-found: error
79
+
80
+ publish:
81
+ needs: build
82
+ runs-on: ubuntu-latest
83
+ environment: pypi
84
+ permissions:
85
+ id-token: write
86
+ steps:
87
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
88
+ with:
89
+ name: dist
90
+ path: dist/
91
+ # Trusted Publishing (OIDC). v1.11.0+ attaches PEP 740 attestations
92
+ # automatically; no long-lived PyPI token is used.
93
+ - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
94
+
95
+ github-release:
96
+ needs: publish
97
+ runs-on: ubuntu-latest
98
+ permissions:
99
+ contents: write
100
+ steps:
101
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
102
+ with:
103
+ persist-credentials: false
104
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
105
+ with:
106
+ name: dist
107
+ path: dist/
108
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
109
+ with:
110
+ name: release-notes
111
+ path: .
112
+ - name: Create the GitHub release
113
+ env:
114
+ GITHUB_TOKEN: ${{ github.token }}
115
+ run: gh release create "$GITHUB_REF_NAME" dist/* --notes-file release-notes.md
@@ -0,0 +1,31 @@
1
+ name: Scorecard
2
+
3
+ on:
4
+ branch_protection_rule:
5
+ schedule:
6
+ - cron: "27 5 * * 1"
7
+ push:
8
+ branches: [main]
9
+
10
+ permissions: read-all
11
+
12
+ jobs:
13
+ analysis:
14
+ name: Scorecard analysis
15
+ runs-on: ubuntu-latest
16
+ permissions:
17
+ contents: read
18
+ security-events: write
19
+ id-token: write
20
+ steps:
21
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
22
+ with:
23
+ persist-credentials: false
24
+ - uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
25
+ with:
26
+ results_file: results.sarif
27
+ results_format: sarif
28
+ publish_results: true
29
+ - uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4
30
+ with:
31
+ sarif_file: results.sarif
@@ -0,0 +1,17 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ build/
5
+ dist/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .coverage
10
+ data_cache/
11
+
12
+ # Maintainer-local context is never published.
13
+ .private/
14
+ .agents/
15
+ .claude/
16
+ agent_docs/
17
+ docs/superpowers/
@@ -0,0 +1,115 @@
1
+ # AGENTS.md — koval-backtrader
2
+
3
+ Context for AI coding agents and their humans. Start here; depth lives in
4
+ [agents_docs/README.md](agents_docs/README.md).
5
+
6
+ ## What this is
7
+
8
+ koval-backtrader runs [koval-engine](https://github.com/koval-finance/koval-engine)
9
+ strategy graphs through [Backtrader](https://github.com/mementum/backtrader).
10
+ It is a plugin, not a framework: the engine defines `BacktestEngineProtocol`
11
+ and discovers implementations through the `koval.backtest_engines` entry-point
12
+ group, and this package is one.
13
+
14
+ The engine is MIT and cannot import Backtrader, which is GPL-3.0. That is the
15
+ entire reason this repository exists as a separate distribution. Installing
16
+ `koval-engine` alone gives you a strategy engine that cannot run a backtest;
17
+ installing this alongside it completes the picture.
18
+
19
+ Distribution: `koval-backtrader`. Import package: `koval_backtrader`.
20
+
21
+ ## Non-negotiables
22
+
23
+ [agents_docs/invariants.md](agents_docs/invariants.md) says which test pins
24
+ each of these and which are the reviewer's job instead. They carry the same
25
+ weight either way.
26
+
27
+ - **GPL-3.0-or-later, and every source file says so.** Each `.py` under `src/`
28
+ starts with `# SPDX-License-Identifier: GPL-3.0-or-later`.
29
+ - **The dependency arrow points one way.** This package imports `koval.engine`
30
+ and `koval.strategy` freely. Nothing here may import application code, and
31
+ nothing in the engine may import this. An import in the wrong direction
32
+ relicenses an MIT codebase by accident.
33
+ - **Never claim the `koval` import namespace.** The engine ships
34
+ `koval/__init__.py` as a regular package; a second distribution adding to it
35
+ shadows unpredictably. This package is top-level `koval_backtrader`.
36
+ - **No real-money code path.** Backtests are simulations over historical
37
+ candles. Never add an order path that reaches a live venue.
38
+ - **English only** in code, comments, docstrings, tests, and docs.
39
+ - **Agents never commit.** No commits, pushes, tags, rebases, merges, or
40
+ history rewrites. Prepare changes, run verification, suggest a commit
41
+ message, stop. All git actions belong to a human.
42
+ - **When a guard test fails, fix the cause — never the guard.**
43
+
44
+ ## Setup
45
+
46
+ ```bash
47
+ python3 -m venv .venv
48
+ .venv/bin/python -m pip install -e ".[dev]"
49
+ ```
50
+
51
+ Requires Python 3.11+. Installing pulls `koval-engine` from PyPI.
52
+
53
+ ## Definition of done
54
+
55
+ ```bash
56
+ ./scripts/verify.sh
57
+ ```
58
+
59
+ Exit code 0 means done: lint, formatting, and the full test suite. Nothing
60
+ else counts, and no prose argument substitutes for it.
61
+
62
+ Every test here needs Backtrader, so unlike the engine there is no marker to
63
+ exclude and no partial run to defend.
64
+
65
+ ## Repository map
66
+
67
+ ```
68
+ src/koval_backtrader/
69
+ ├── backtest_runner.py BacktraderBacktestEngine and the create_engine factory
70
+ ├── bt_adapter.py DeclarativeStrategy → bt.Strategy bridge, HTF injection
71
+ ├── bt_analyzers.py equity-curve and closed-trade analyzers
72
+ └── oco_patch.py guard against a Backtrader OCO ghost-trade bug
73
+ ```
74
+
75
+ `tests/` is flat and mirrors those module names.
76
+
77
+ ## The seam
78
+
79
+ ```toml
80
+ [project.entry-points."koval.backtest_engines"]
81
+ backtrader = "koval_backtrader.backtest_runner:create_engine"
82
+ ```
83
+
84
+ `load_backtest_engine()` reads that group, takes the entry point named
85
+ `backtrader`, imports it, and calls it. Installing the package is the whole
86
+ configuration story — no environment variable, no import, no wiring. The
87
+ `KOVAL_BACKTEST_ENGINE` variable exists as an override for development and
88
+ takes a module path, not an entry-point name.
89
+
90
+ `tests/test_entry_point.py` is the guard, and it is the most important file
91
+ here: if it fails, `koval backtest` is broken for every user even when every
92
+ other test is green.
93
+
94
+ ## How to work here
95
+
96
+ 1. Restate the task and name what is out of scope before editing anything.
97
+ 2. Write the failing test first and watch it fail. This package decides where
98
+ simulated orders fill; calculation or state-transition logic without a test
99
+ that was observed failing is not accepted.
100
+ 3. Implement the minimum that makes it pass. No drive-by refactoring.
101
+ 4. Run `./scripts/verify.sh`.
102
+ 5. Review your own diff, report, and stop before any git action.
103
+
104
+ Full workflow: [agents_docs/agent_workflow.md](agents_docs/agent_workflow.md).
105
+
106
+ ## Where to read next
107
+
108
+ | Task | Read first |
109
+ |---|---|
110
+ | Anything touching licensing or the seam | [agents_docs/invariants.md](agents_docs/invariants.md) |
111
+ | Adapter internals, fills, event flow | [agents_docs/architecture.md](agents_docs/architecture.md) |
112
+ | Test failure or unexpected behaviour | [agents_docs/troubleshooting.md](agents_docs/troubleshooting.md) |
113
+ | Writing or changing tests | [agents_docs/testing.md](agents_docs/testing.md) |
114
+ | Cutting a release | [agents_docs/release_process.md](agents_docs/release_process.md) |
115
+ | Everything else | [agents_docs/README.md](agents_docs/README.md) |
@@ -0,0 +1,37 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.9.0] - 2026-08-03
8
+
9
+ First public release. Extracted from a private monorepo with a clean history.
10
+
11
+ ### Added
12
+
13
+ - `BacktraderBacktestEngine`, an implementation of koval-engine's
14
+ `BacktestEngineProtocol` that runs typed strategy graphs through Backtrader's
15
+ `Cerebro` and returns plain metrics, closed trades, and an equity curve.
16
+ - Registration under the `koval.backtest_engines` entry-point group as
17
+ `backtrader`, so installing the package is the entire configuration —
18
+ `load_backtest_engine()` finds it with no environment variable.
19
+ - `BTStrategyAdapter` and the `make_bt_strategy_class` factory, bridging
20
+ `DeclarativeStrategy` to `bt.Strategy`: bar-window array injection, higher
21
+ timeframe feeds, bracket placement, trailing and breakeven exit updates, and
22
+ an engine-event stream that makes a run auditable after the fact.
23
+ - `TradeListAnalyzer` and `EquityCurveAnalyzer` for result extraction.
24
+ - `apply_oco_guard()`, fixing a Backtrader bug where a take-profit and a
25
+ stop-loss both eligible within one bar could both fill, producing a trade
26
+ that never happened.
27
+ - Guard tests covering the entry-point seam, GPL SPDX headers, the published
28
+ package surface, and the release pipeline.
29
+
30
+ ### Security
31
+
32
+ - No real-money code path. This package replays historical candles through a
33
+ simulated broker; it holds no credentials and opens no venue connection.
34
+ - Releases publish to PyPI through Trusted Publishing (OIDC) with PEP 740
35
+ attestations. No long-lived PyPI credential is used.
36
+
37
+ [0.9.0]: https://github.com/koval-finance/koval-backtrader/releases/tag/v0.9.0
@@ -0,0 +1,9 @@
1
+ # CLAUDE.md
2
+
3
+ Claude Code entry file for this repository.
4
+
5
+ All project context lives in [AGENTS.md](AGENTS.md). Read it before doing
6
+ anything else; the definition of done is `./scripts/verify.sh` exiting 0.
7
+
8
+ Maintainer-only: if `.private/CONTEXT.md` exists in your checkout, read it
9
+ too. Contributors will not have this file; its absence is normal.