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.
- koval_backtrader-0.9.0/.cursor/rules/koval-backtrader.mdc +10 -0
- koval_backtrader-0.9.0/.github/CODEOWNERS +2 -0
- koval_backtrader-0.9.0/.github/ISSUE_TEMPLATE/bug_report.yml +76 -0
- koval_backtrader-0.9.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- koval_backtrader-0.9.0/.github/ISSUE_TEMPLATE/feature_request.yml +44 -0
- koval_backtrader-0.9.0/.github/PULL_REQUEST_TEMPLATE.md +22 -0
- koval_backtrader-0.9.0/.github/copilot-instructions.md +6 -0
- koval_backtrader-0.9.0/.github/dependabot.yml +10 -0
- koval_backtrader-0.9.0/.github/workflows/ci.yml +57 -0
- koval_backtrader-0.9.0/.github/workflows/mirror.yml +31 -0
- koval_backtrader-0.9.0/.github/workflows/release.yml +115 -0
- koval_backtrader-0.9.0/.github/workflows/scorecard.yml +31 -0
- koval_backtrader-0.9.0/.gitignore +17 -0
- koval_backtrader-0.9.0/AGENTS.md +115 -0
- koval_backtrader-0.9.0/CHANGELOG.md +37 -0
- koval_backtrader-0.9.0/CLAUDE.md +9 -0
- koval_backtrader-0.9.0/CODE_OF_CONDUCT.md +132 -0
- koval_backtrader-0.9.0/CONTRIBUTING.md +90 -0
- koval_backtrader-0.9.0/GEMINI.md +6 -0
- koval_backtrader-0.9.0/LICENSE +674 -0
- koval_backtrader-0.9.0/MANIFEST.in +15 -0
- koval_backtrader-0.9.0/PKG-INFO +140 -0
- koval_backtrader-0.9.0/README.md +105 -0
- koval_backtrader-0.9.0/SECURITY.md +44 -0
- koval_backtrader-0.9.0/agents_docs/README.md +39 -0
- koval_backtrader-0.9.0/agents_docs/agent_workflow.md +52 -0
- koval_backtrader-0.9.0/agents_docs/architecture.md +103 -0
- koval_backtrader-0.9.0/agents_docs/invariants.md +74 -0
- koval_backtrader-0.9.0/agents_docs/release_process.md +43 -0
- koval_backtrader-0.9.0/agents_docs/testing.md +57 -0
- koval_backtrader-0.9.0/agents_docs/troubleshooting.md +38 -0
- koval_backtrader-0.9.0/examples/run_backtest.py +38 -0
- koval_backtrader-0.9.0/pyproject.toml +75 -0
- koval_backtrader-0.9.0/scripts/verify.sh +14 -0
- koval_backtrader-0.9.0/setup.cfg +4 -0
- koval_backtrader-0.9.0/src/koval_backtrader/__init__.py +22 -0
- koval_backtrader-0.9.0/src/koval_backtrader/backtest_runner.py +116 -0
- koval_backtrader-0.9.0/src/koval_backtrader/bt_adapter.py +446 -0
- koval_backtrader-0.9.0/src/koval_backtrader/bt_analyzers.py +111 -0
- koval_backtrader-0.9.0/src/koval_backtrader/oco_patch.py +148 -0
- koval_backtrader-0.9.0/src/koval_backtrader/py.typed +0 -0
- koval_backtrader-0.9.0/src/koval_backtrader.egg-info/PKG-INFO +140 -0
- koval_backtrader-0.9.0/src/koval_backtrader.egg-info/SOURCES.txt +62 -0
- koval_backtrader-0.9.0/src/koval_backtrader.egg-info/dependency_links.txt +1 -0
- koval_backtrader-0.9.0/src/koval_backtrader.egg-info/entry_points.txt +2 -0
- koval_backtrader-0.9.0/src/koval_backtrader.egg-info/requires.txt +12 -0
- koval_backtrader-0.9.0/src/koval_backtrader.egg-info/top_level.txt +1 -0
- koval_backtrader-0.9.0/tests/test_agents_docs.py +98 -0
- koval_backtrader-0.9.0/tests/test_backtest_runner.py +106 -0
- koval_backtrader-0.9.0/tests/test_block_assembler_integration.py +78 -0
- koval_backtrader-0.9.0/tests/test_bt_adapter.py +361 -0
- koval_backtrader-0.9.0/tests/test_bt_adapter_htf.py +67 -0
- koval_backtrader-0.9.0/tests/test_bt_analyzers.py +101 -0
- koval_backtrader-0.9.0/tests/test_entry_point.py +84 -0
- koval_backtrader-0.9.0/tests/test_examples.py +71 -0
- koval_backtrader-0.9.0/tests/test_license_headers.py +50 -0
- koval_backtrader-0.9.0/tests/test_oco_patch.py +98 -0
- koval_backtrader-0.9.0/tests/test_package_metadata.py +89 -0
- koval_backtrader-0.9.0/tests/test_public_language.py +125 -0
- koval_backtrader-0.9.0/tests/test_public_surface.py +99 -0
- koval_backtrader-0.9.0/tests/test_release_workflow.py +106 -0
- koval_backtrader-0.9.0/tests/test_sdist_contents.py +118 -0
- koval_backtrader-0.9.0/tests/test_state_injection_arrays.py +100 -0
- 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,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,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.
|