koval-engine 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_engine-0.9.0/.cursor/rules/koval-engine.mdc +9 -0
- koval_engine-0.9.0/.github/CODEOWNERS +2 -0
- koval_engine-0.9.0/.github/ISSUE_TEMPLATE/bug_report.yml +65 -0
- koval_engine-0.9.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- koval_engine-0.9.0/.github/ISSUE_TEMPLATE/feature_request.yml +42 -0
- koval_engine-0.9.0/.github/PULL_REQUEST_TEMPLATE.md +21 -0
- koval_engine-0.9.0/.github/copilot-instructions.md +5 -0
- koval_engine-0.9.0/.github/dependabot.yml +10 -0
- koval_engine-0.9.0/.github/workflows/ci.yml +57 -0
- koval_engine-0.9.0/.github/workflows/mirror.yml +31 -0
- koval_engine-0.9.0/.github/workflows/release.yml +115 -0
- koval_engine-0.9.0/.github/workflows/scorecard.yml +31 -0
- koval_engine-0.9.0/.gitignore +17 -0
- koval_engine-0.9.0/AGENTS.md +95 -0
- koval_engine-0.9.0/CHANGELOG.md +34 -0
- koval_engine-0.9.0/CLAUDE.md +9 -0
- koval_engine-0.9.0/CODE_OF_CONDUCT.md +132 -0
- koval_engine-0.9.0/CONTRIBUTING.md +88 -0
- koval_engine-0.9.0/GEMINI.md +6 -0
- koval_engine-0.9.0/LICENSE +21 -0
- koval_engine-0.9.0/MANIFEST.in +15 -0
- koval_engine-0.9.0/PKG-INFO +174 -0
- koval_engine-0.9.0/README.md +135 -0
- koval_engine-0.9.0/SECURITY.md +50 -0
- koval_engine-0.9.0/agents_docs/README.md +47 -0
- koval_engine-0.9.0/agents_docs/adding_a_block.md +42 -0
- koval_engine-0.9.0/agents_docs/agent_workflow.md +40 -0
- koval_engine-0.9.0/agents_docs/architecture.md +53 -0
- koval_engine-0.9.0/agents_docs/code_style.md +31 -0
- koval_engine-0.9.0/agents_docs/exchanges_and_data.md +42 -0
- koval_engine-0.9.0/agents_docs/glossary.md +46 -0
- koval_engine-0.9.0/agents_docs/graph_contracts.md +63 -0
- koval_engine-0.9.0/agents_docs/invariants.md +25 -0
- koval_engine-0.9.0/agents_docs/release_process.md +43 -0
- koval_engine-0.9.0/agents_docs/testing.md +61 -0
- koval_engine-0.9.0/agents_docs/troubleshooting.md +60 -0
- koval_engine-0.9.0/examples/generate_sample.py +60 -0
- koval_engine-0.9.0/examples/run_backtest.py +29 -0
- koval_engine-0.9.0/pyproject.toml +79 -0
- koval_engine-0.9.0/scripts/verify.sh +14 -0
- koval_engine-0.9.0/setup.cfg +4 -0
- koval_engine-0.9.0/src/koval/__init__.py +7 -0
- koval_engine-0.9.0/src/koval/_version.py +7 -0
- koval_engine-0.9.0/src/koval/cli/__init__.py +7 -0
- koval_engine-0.9.0/src/koval/cli/data.py +27 -0
- koval_engine-0.9.0/src/koval/cli/main.py +239 -0
- koval_engine-0.9.0/src/koval/engine/__init__.py +0 -0
- koval_engine-0.9.0/src/koval/engine/account_state.py +105 -0
- koval_engine-0.9.0/src/koval/engine/backtest_engine.py +114 -0
- koval_engine-0.9.0/src/koval/engine/broker.py +151 -0
- koval_engine-0.9.0/src/koval/engine/client_order_id.py +22 -0
- koval_engine-0.9.0/src/koval/engine/engine_events.py +25 -0
- koval_engine-0.9.0/src/koval/engine/execution_settings.py +170 -0
- koval_engine-0.9.0/src/koval/engine/live_engine.py +989 -0
- koval_engine-0.9.0/src/koval/engine/live_feed.py +216 -0
- koval_engine-0.9.0/src/koval/engine/logger.py +146 -0
- koval_engine-0.9.0/src/koval/engine/paper_broker.py +544 -0
- koval_engine-0.9.0/src/koval/engine/time_range.py +11 -0
- koval_engine-0.9.0/src/koval/engine/timeframe_utils.py +29 -0
- koval_engine-0.9.0/src/koval/engine/trade_context.py +46 -0
- koval_engine-0.9.0/src/koval/engine/trade_indicators.py +169 -0
- koval_engine-0.9.0/src/koval/engine/trade_metrics.py +50 -0
- koval_engine-0.9.0/src/koval/engine/trade_narrator.py +27 -0
- koval_engine-0.9.0/src/koval/engine/venue_metadata.py +164 -0
- koval_engine-0.9.0/src/koval/examples/__init__.py +25 -0
- koval_engine-0.9.0/src/koval/examples/data/README.md +5 -0
- koval_engine-0.9.0/src/koval/examples/data/sample-1h.csv +1201 -0
- koval_engine-0.9.0/src/koval/examples/graphs/ema_cross_trend.json +21 -0
- koval_engine-0.9.0/src/koval/exchanges/__init__.py +47 -0
- koval_engine-0.9.0/src/koval/exchanges/auth.py +76 -0
- koval_engine-0.9.0/src/koval/exchanges/base.py +180 -0
- koval_engine-0.9.0/src/koval/exchanges/binance.py +148 -0
- koval_engine-0.9.0/src/koval/exchanges/binance_sandbox.py +901 -0
- koval_engine-0.9.0/src/koval/exchanges/ohlcv_cache.py +221 -0
- koval_engine-0.9.0/src/koval/exchanges/sandbox_factory.py +39 -0
- koval_engine-0.9.0/src/koval/exchanges/whitebit.py +153 -0
- koval_engine-0.9.0/src/koval/exchanges/whitebit_sandbox.py +35 -0
- koval_engine-0.9.0/src/koval/py.typed +1 -0
- koval_engine-0.9.0/src/koval/strategy/__init__.py +0 -0
- koval_engine-0.9.0/src/koval/strategy/base/__init__.py +0 -0
- koval_engine-0.9.0/src/koval/strategy/base/declarative.py +110 -0
- koval_engine-0.9.0/src/koval/strategy/base/trade_setup.py +52 -0
- koval_engine-0.9.0/src/koval/strategy/block_assembler.py +62 -0
- koval_engine-0.9.0/src/koval/strategy/graph/__init__.py +0 -0
- koval_engine-0.9.0/src/koval/strategy/graph/compat.py +280 -0
- koval_engine-0.9.0/src/koval/strategy/graph/domains.py +40 -0
- koval_engine-0.9.0/src/koval/strategy/graph/entities.py +108 -0
- koval_engine-0.9.0/src/koval/strategy/graph/executor.py +144 -0
- koval_engine-0.9.0/src/koval/strategy/graph/node.py +82 -0
- koval_engine-0.9.0/src/koval/strategy/graph/ports.py +24 -0
- koval_engine-0.9.0/src/koval/strategy/graph/registry.py +44 -0
- koval_engine-0.9.0/src/koval/strategy/graph/state_store.py +17 -0
- koval_engine-0.9.0/src/koval/strategy/graph/strategy.py +159 -0
- koval_engine-0.9.0/src/koval/strategy/graph/validation.py +141 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/__init__.py +0 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/_math.py +132 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/exits/__init__.py +0 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/exits/breakeven.py +25 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/exits/fixed.py +27 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/exits/pricing.py +42 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/exits/trailing.py +22 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/filters/__init__.py +0 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/filters/momentum.py +55 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/filters/trend.py +83 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/filters/volatility.py +42 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/interp/__init__.py +0 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/interp/scoring.py +28 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/risk/__init__.py +0 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/risk/gates.py +55 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/risk/position_sizer.py +67 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/risk/sizing.py +15 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/signals/__init__.py +0 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/signals/candlesticks.py +74 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/signals/smc.py +110 -0
- koval_engine-0.9.0/src/koval/strategy/helpers/signals/technical.py +52 -0
- koval_engine-0.9.0/src/koval/strategy/nodes/__init__.py +12 -0
- koval_engine-0.9.0/src/koval/strategy/nodes/aggregator.py +186 -0
- koval_engine-0.9.0/src/koval/strategy/nodes/exec_pipeline.py +372 -0
- koval_engine-0.9.0/src/koval/strategy/nodes/execution.py +93 -0
- koval_engine-0.9.0/src/koval/strategy/nodes/fact.py +376 -0
- koval_engine-0.9.0/src/koval/strategy/nodes/interp.py +120 -0
- koval_engine-0.9.0/src/koval/strategy/nodes/policy.py +233 -0
- koval_engine-0.9.0/src/koval/strategy/nodes/scoring.py +276 -0
- koval_engine-0.9.0/src/koval/strategy/nodes/state.py +116 -0
- koval_engine-0.9.0/src/koval/strategy/presets/__init__.py +8 -0
- koval_engine-0.9.0/src/koval/strategy/presets/risk_pipeline_demo.py +52 -0
- koval_engine-0.9.0/src/koval/strategy/presets/sweep_choch_reversal.py +73 -0
- koval_engine-0.9.0/src/koval/strategy/promotion_gates.py +112 -0
- koval_engine-0.9.0/src/koval/strategy/registry.py +778 -0
- koval_engine-0.9.0/src/koval/strategy/schemas.py +225 -0
- koval_engine-0.9.0/src/koval_engine.egg-info/PKG-INFO +174 -0
- koval_engine-0.9.0/src/koval_engine.egg-info/SOURCES.txt +252 -0
- koval_engine-0.9.0/src/koval_engine.egg-info/dependency_links.txt +1 -0
- koval_engine-0.9.0/src/koval_engine.egg-info/entry_points.txt +2 -0
- koval_engine-0.9.0/src/koval_engine.egg-info/requires.txt +16 -0
- koval_engine-0.9.0/src/koval_engine.egg-info/top_level.txt +1 -0
- koval_engine-0.9.0/tests/__init__.py +0 -0
- koval_engine-0.9.0/tests/cli/__init__.py +0 -0
- koval_engine-0.9.0/tests/cli/conftest.py +26 -0
- koval_engine-0.9.0/tests/cli/test_cli_backtest_bad_engine.py +36 -0
- koval_engine-0.9.0/tests/cli/test_cli_backtest_fetch.py +98 -0
- koval_engine-0.9.0/tests/cli/test_cli_backtest_no_engine.py +30 -0
- koval_engine-0.9.0/tests/cli/test_cli_backtest_offline.py +25 -0
- koval_engine-0.9.0/tests/cli/test_cli_blocks.py +22 -0
- koval_engine-0.9.0/tests/cli/test_cli_data.py +50 -0
- koval_engine-0.9.0/tests/cli/test_cli_examples.py +62 -0
- koval_engine-0.9.0/tests/cli/test_cli_validate.py +47 -0
- koval_engine-0.9.0/tests/conftest.py +3 -0
- koval_engine-0.9.0/tests/engine/__init__.py +0 -0
- koval_engine-0.9.0/tests/engine/live_fixtures.py +51 -0
- koval_engine-0.9.0/tests/engine/test_account_state.py +75 -0
- koval_engine-0.9.0/tests/engine/test_backtest_engine.py +47 -0
- koval_engine-0.9.0/tests/engine/test_broker.py +122 -0
- koval_engine-0.9.0/tests/engine/test_client_order_id.py +45 -0
- koval_engine-0.9.0/tests/engine/test_engine_events.py +63 -0
- koval_engine-0.9.0/tests/engine/test_engine_loader.py +60 -0
- koval_engine-0.9.0/tests/engine/test_execution_settings.py +124 -0
- koval_engine-0.9.0/tests/engine/test_live_engine.py +1273 -0
- koval_engine-0.9.0/tests/engine/test_live_feed.py +190 -0
- koval_engine-0.9.0/tests/engine/test_live_parity.py +53 -0
- koval_engine-0.9.0/tests/engine/test_logger.py +100 -0
- koval_engine-0.9.0/tests/engine/test_paper_broker.py +526 -0
- koval_engine-0.9.0/tests/engine/test_protocol_version.py +26 -0
- koval_engine-0.9.0/tests/engine/test_time_range.py +16 -0
- koval_engine-0.9.0/tests/engine/test_timeframe_utils.py +40 -0
- koval_engine-0.9.0/tests/engine/test_trade_context.py +35 -0
- koval_engine-0.9.0/tests/engine/test_trade_indicators.py +119 -0
- koval_engine-0.9.0/tests/engine/test_trade_metrics.py +66 -0
- koval_engine-0.9.0/tests/engine/test_trade_narrator.py +32 -0
- koval_engine-0.9.0/tests/engine/test_venue_metadata.py +207 -0
- koval_engine-0.9.0/tests/exchanges/__init__.py +0 -0
- koval_engine-0.9.0/tests/exchanges/conftest.py +40 -0
- koval_engine-0.9.0/tests/exchanges/test_auth.py +56 -0
- koval_engine-0.9.0/tests/exchanges/test_base.py +76 -0
- koval_engine-0.9.0/tests/exchanges/test_binance.py +236 -0
- koval_engine-0.9.0/tests/exchanges/test_binance_sandbox.py +1173 -0
- koval_engine-0.9.0/tests/exchanges/test_exchange_factory.py +26 -0
- koval_engine-0.9.0/tests/exchanges/test_ohlcv_cache.py +469 -0
- koval_engine-0.9.0/tests/exchanges/test_sandbox_factory.py +40 -0
- koval_engine-0.9.0/tests/exchanges/test_whitebit.py +211 -0
- koval_engine-0.9.0/tests/exchanges/test_whitebit_sandbox.py +32 -0
- koval_engine-0.9.0/tests/safety/__init__.py +0 -0
- koval_engine-0.9.0/tests/safety/test_no_real_money_path.py +128 -0
- koval_engine-0.9.0/tests/smoke/test_binance_sandbox_manual.py +52 -0
- koval_engine-0.9.0/tests/strategy/__init__.py +0 -0
- koval_engine-0.9.0/tests/strategy/graph/__init__.py +0 -0
- koval_engine-0.9.0/tests/strategy/graph/test_barcontext_account.py +14 -0
- koval_engine-0.9.0/tests/strategy/graph/test_compat.py +62 -0
- koval_engine-0.9.0/tests/strategy/graph/test_compat_golden.py +45 -0
- koval_engine-0.9.0/tests/strategy/graph/test_domains.py +23 -0
- koval_engine-0.9.0/tests/strategy/graph/test_dynamic_exit.py +84 -0
- koval_engine-0.9.0/tests/strategy/graph/test_entities.py +96 -0
- koval_engine-0.9.0/tests/strategy/graph/test_executor.py +292 -0
- koval_engine-0.9.0/tests/strategy/graph/test_graph_strategy.py +141 -0
- koval_engine-0.9.0/tests/strategy/graph/test_graph_strategy_blocked.py +92 -0
- koval_engine-0.9.0/tests/strategy/graph/test_interp_chain.py +212 -0
- koval_engine-0.9.0/tests/strategy/graph/test_interp_full_engine_golden.py +163 -0
- koval_engine-0.9.0/tests/strategy/graph/test_ports.py +30 -0
- koval_engine-0.9.0/tests/strategy/graph/test_reasoning_surfacing.py +98 -0
- koval_engine-0.9.0/tests/strategy/graph/test_registry.py +91 -0
- koval_engine-0.9.0/tests/strategy/graph/test_risk_pipeline_golden.py +166 -0
- koval_engine-0.9.0/tests/strategy/graph/test_state_store.py +21 -0
- koval_engine-0.9.0/tests/strategy/graph/test_validation.py +221 -0
- koval_engine-0.9.0/tests/strategy/graph/test_validation_cycle.py +9 -0
- koval_engine-0.9.0/tests/strategy/helpers/__init__.py +0 -0
- koval_engine-0.9.0/tests/strategy/helpers/exits/__init__.py +0 -0
- koval_engine-0.9.0/tests/strategy/helpers/exits/test_breakeven.py +83 -0
- koval_engine-0.9.0/tests/strategy/helpers/exits/test_fixed.py +45 -0
- koval_engine-0.9.0/tests/strategy/helpers/exits/test_pricing.py +40 -0
- koval_engine-0.9.0/tests/strategy/helpers/exits/test_trailing.py +79 -0
- koval_engine-0.9.0/tests/strategy/helpers/filters/__init__.py +0 -0
- koval_engine-0.9.0/tests/strategy/helpers/filters/test_momentum.py +111 -0
- koval_engine-0.9.0/tests/strategy/helpers/filters/test_trend.py +54 -0
- koval_engine-0.9.0/tests/strategy/helpers/filters/test_volatility.py +54 -0
- koval_engine-0.9.0/tests/strategy/helpers/interp/__init__.py +0 -0
- koval_engine-0.9.0/tests/strategy/helpers/interp/test_scoring.py +26 -0
- koval_engine-0.9.0/tests/strategy/helpers/risk/__init__.py +0 -0
- koval_engine-0.9.0/tests/strategy/helpers/risk/test_gates.py +118 -0
- koval_engine-0.9.0/tests/strategy/helpers/risk/test_position_sizer.py +186 -0
- koval_engine-0.9.0/tests/strategy/helpers/risk/test_sizing.py +24 -0
- koval_engine-0.9.0/tests/strategy/helpers/signals/__init__.py +0 -0
- koval_engine-0.9.0/tests/strategy/helpers/signals/test_candlesticks.py +114 -0
- koval_engine-0.9.0/tests/strategy/helpers/signals/test_smc.py +122 -0
- koval_engine-0.9.0/tests/strategy/helpers/signals/test_technical.py +72 -0
- koval_engine-0.9.0/tests/strategy/helpers/test_math.py +110 -0
- koval_engine-0.9.0/tests/strategy/nodes/__init__.py +0 -0
- koval_engine-0.9.0/tests/strategy/nodes/test_aggregator.py +192 -0
- koval_engine-0.9.0/tests/strategy/nodes/test_execution_nodes.py +340 -0
- koval_engine-0.9.0/tests/strategy/nodes/test_fact_nodes.py +72 -0
- koval_engine-0.9.0/tests/strategy/nodes/test_interp_nodes.py +63 -0
- koval_engine-0.9.0/tests/strategy/nodes/test_policy_nodes.py +38 -0
- koval_engine-0.9.0/tests/strategy/nodes/test_scoring_nodes.py +276 -0
- koval_engine-0.9.0/tests/strategy/nodes/test_state_nodes.py +45 -0
- koval_engine-0.9.0/tests/strategy/presets/__init__.py +0 -0
- koval_engine-0.9.0/tests/strategy/presets/test_risk_pipeline_demo.py +8 -0
- koval_engine-0.9.0/tests/strategy/presets/test_sweep_choch_reversal.py +48 -0
- koval_engine-0.9.0/tests/strategy/test_block_assembler.py +331 -0
- koval_engine-0.9.0/tests/strategy/test_declarative.py +175 -0
- koval_engine-0.9.0/tests/strategy/test_promotion_gates.py +129 -0
- koval_engine-0.9.0/tests/strategy/test_registry_blocks.py +365 -0
- koval_engine-0.9.0/tests/strategy/test_registry_strategies.py +126 -0
- koval_engine-0.9.0/tests/strategy/test_schemas.py +122 -0
- koval_engine-0.9.0/tests/strategy/test_trade_setup.py +199 -0
- koval_engine-0.9.0/tests/test_agents_docs.py +96 -0
- koval_engine-0.9.0/tests/test_example_data.py +58 -0
- koval_engine-0.9.0/tests/test_license_boundary.py +79 -0
- koval_engine-0.9.0/tests/test_package_metadata.py +29 -0
- koval_engine-0.9.0/tests/test_public_language.py +125 -0
- koval_engine-0.9.0/tests/test_public_surface.py +99 -0
- koval_engine-0.9.0/tests/test_readme_quickstart.py +83 -0
- koval_engine-0.9.0/tests/test_release_docs.py +69 -0
- koval_engine-0.9.0/tests/test_release_workflow.py +65 -0
- koval_engine-0.9.0/tests/test_sdist_contents.py +118 -0
- koval_engine-0.9.0/tests/test_version.py +21 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: koval-engine 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: no real-money code path, no backtrader import, no new
|
|
9
|
+
runtime dependencies, never run git write commands.
|
|
@@ -0,0 +1,65 @@
|
|
|
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-engine/blob/main/SECURITY.md) for private reporting.
|
|
9
|
+
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: what-happened
|
|
12
|
+
attributes:
|
|
13
|
+
label: What happened
|
|
14
|
+
description: What did you observe? Paste the full error or the incorrect output.
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: reproduction
|
|
20
|
+
attributes:
|
|
21
|
+
label: How to reproduce
|
|
22
|
+
description: The exact CLI command or Python snippet, plus the strategy graph JSON if one is involved. A reproduction that runs against the bundled example data is ideal.
|
|
23
|
+
render: shell
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
|
|
27
|
+
- type: textarea
|
|
28
|
+
id: expected
|
|
29
|
+
attributes:
|
|
30
|
+
label: What you expected instead
|
|
31
|
+
validations:
|
|
32
|
+
required: true
|
|
33
|
+
|
|
34
|
+
- type: input
|
|
35
|
+
id: engine-version
|
|
36
|
+
attributes:
|
|
37
|
+
label: koval-engine version
|
|
38
|
+
description: Output of `koval --version`.
|
|
39
|
+
placeholder: "0.9.0"
|
|
40
|
+
validations:
|
|
41
|
+
required: true
|
|
42
|
+
|
|
43
|
+
- type: input
|
|
44
|
+
id: adapter-version
|
|
45
|
+
attributes:
|
|
46
|
+
label: Backtest engine package and version
|
|
47
|
+
description: e.g. package-name 1.2.3, or "none" if the problem does not involve a backtest.
|
|
48
|
+
validations:
|
|
49
|
+
required: false
|
|
50
|
+
|
|
51
|
+
- type: input
|
|
52
|
+
id: python-version
|
|
53
|
+
attributes:
|
|
54
|
+
label: Python version
|
|
55
|
+
placeholder: "3.12.4"
|
|
56
|
+
validations:
|
|
57
|
+
required: true
|
|
58
|
+
|
|
59
|
+
- type: input
|
|
60
|
+
id: os
|
|
61
|
+
attributes:
|
|
62
|
+
label: Operating system
|
|
63
|
+
placeholder: "macOS 15.2 / Ubuntu 24.04"
|
|
64
|
+
validations:
|
|
65
|
+
required: true
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest a capability the 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
|
+
Note that real-money trading is permanently out of scope: the engine is built so that no code path reaches a real-money endpoint, and requests to add one will be closed.
|
|
11
|
+
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: problem
|
|
14
|
+
attributes:
|
|
15
|
+
label: The problem
|
|
16
|
+
description: What are you trying to do that the engine makes difficult or impossible? Describe the situation, not the solution.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: solution
|
|
22
|
+
attributes:
|
|
23
|
+
label: Proposed solution
|
|
24
|
+
description: What you think should change. If it affects a public contract — a block's parameters, an entity on a graph edge, the engine protocol — say so explicitly.
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
|
|
28
|
+
- type: textarea
|
|
29
|
+
id: alternatives
|
|
30
|
+
attributes:
|
|
31
|
+
label: Alternatives considered
|
|
32
|
+
description: What you tried, or why an existing block or a custom backtest engine plugin does not solve it.
|
|
33
|
+
validations:
|
|
34
|
+
required: false
|
|
35
|
+
|
|
36
|
+
- type: checkboxes
|
|
37
|
+
id: dependencies
|
|
38
|
+
attributes:
|
|
39
|
+
label: Dependencies
|
|
40
|
+
options:
|
|
41
|
+
- label: This would not require a new runtime dependency, or I have explained below why one is unavoidable.
|
|
42
|
+
required: false
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
- [ ] `pytest -m "not backtrader" -q` passes
|
|
13
|
+
- [ ] `ruff check .` and `ruff format --check .` are clean
|
|
14
|
+
- [ ] Every commit is signed off (`git commit -s`) — CI enforces this
|
|
15
|
+
- [ ] No new runtime dependency (or the reason for one is explained above)
|
|
16
|
+
- [ ] No file imports `backtrader` or `koval.adapters.backtrader`
|
|
17
|
+
- [ ] `CHANGELOG.md` updated under `[Unreleased]`, if this is user-visible
|
|
18
|
+
|
|
19
|
+
## Notes for the reviewer
|
|
20
|
+
|
|
21
|
+
<!-- Anything you are unsure about, or a decision worth a second opinion. Optional. -->
|
|
@@ -0,0 +1,5 @@
|
|
|
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: no real-money code path, no
|
|
4
|
+
`backtrader` import, no new runtime dependencies, and never run git write
|
|
5
|
+
commands — 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 default suite — the
|
|
31
|
+
# same gates as the release workflow, pinned to it by
|
|
32
|
+
# tests/test_agents_docs.py. The licence-boundary, public-surface,
|
|
33
|
+
# public-language, and agent-docs guards are pytest tests and run
|
|
34
|
+
# 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-engine.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 -m "not backtrader" -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,95 @@
|
|
|
1
|
+
# AGENTS.md — koval-engine
|
|
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-engine is the MIT-licensed core of a trading-strategy platform: a
|
|
9
|
+
typed dataflow strategy engine, a block library, exchange data adapters, and
|
|
10
|
+
sandbox brokers. It is published on PyPI as `koval-engine`; the import
|
|
11
|
+
package is `koval`. There is no real-money trading path, by design and by
|
|
12
|
+
test.
|
|
13
|
+
|
|
14
|
+
## Non-negotiables
|
|
15
|
+
|
|
16
|
+
Tests pin most of these; [agents_docs/invariants.md](agents_docs/invariants.md)
|
|
17
|
+
says exactly which, and marks the rest as the reviewer's job instead. All six
|
|
18
|
+
carry the same weight regardless of which enforces them.
|
|
19
|
+
|
|
20
|
+
- **No real-money code path.** Only `paper` and `binance_sandbox` execution
|
|
21
|
+
modes exist. Never add, enable, or assume another.
|
|
22
|
+
- **MIT only.** No file imports `backtrader` or any package derived from it.
|
|
23
|
+
Backtest engines are separate plugins found through the
|
|
24
|
+
`koval.backtest_engines` entry-point group.
|
|
25
|
+
- **No new runtime dependencies.** The list is exactly: `numpy`, `pandas`,
|
|
26
|
+
`pyarrow`, `portalocker`, `pydantic`, `requests`. Open an issue before
|
|
27
|
+
proposing a seventh.
|
|
28
|
+
- **English only** in code, comments, docstrings, tests, and docs.
|
|
29
|
+
- **Agents never commit.** No commits, pushes, tags, rebases, merges, or
|
|
30
|
+
history rewrites. Prepare changes, run verification, suggest a commit
|
|
31
|
+
message, stop. All git actions belong to a human.
|
|
32
|
+
- **When a guard test fails, fix the cause — never the guard.**
|
|
33
|
+
|
|
34
|
+
## Setup
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
python3 -m venv .venv
|
|
38
|
+
.venv/bin/python -m pip install -e ".[dev]"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Requires Python 3.11+.
|
|
42
|
+
|
|
43
|
+
## Definition of done
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
./scripts/verify.sh
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Exit code 0 means done: lint, formatting, and the full default test suite.
|
|
50
|
+
Nothing else counts, and no prose argument substitutes for it.
|
|
51
|
+
|
|
52
|
+
Do not install `backtrader` into this repository's virtualenv — tests marked
|
|
53
|
+
`backtrader` belong to a separately distributed GPL plugin and are excluded
|
|
54
|
+
by the default command.
|
|
55
|
+
|
|
56
|
+
## Repository map
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
src/koval/
|
|
60
|
+
├── engine/ backtest protocol, live engine, paper broker, metrics, account state
|
|
61
|
+
├── strategy/
|
|
62
|
+
│ ├── base/ DeclarativeStrategy ABC, TradeSetup, EntryConfig
|
|
63
|
+
│ ├── helpers/ pure block functions — no framework, no state, no I/O
|
|
64
|
+
│ ├── graph/ typed dataflow engine: entities, domains, ports, executor
|
|
65
|
+
│ ├── nodes/ typed nodes wrapping the pure helpers
|
|
66
|
+
│ ├── presets/ preset graph builders
|
|
67
|
+
│ ├── registry.py BLOCK_CATALOG and STRATEGY_REGISTRY
|
|
68
|
+
│ └── schemas.py Pydantic parameter models per block
|
|
69
|
+
├── exchanges/ data adapters, OHLCV cache, sandbox brokers
|
|
70
|
+
└── cli/ the `koval` console script
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Tests mirror this layout under `tests/`.
|
|
74
|
+
|
|
75
|
+
## How to work here
|
|
76
|
+
|
|
77
|
+
1. Restate the task and name what is out of scope before editing anything.
|
|
78
|
+
2. Write the failing test first and watch it fail. Calculation or
|
|
79
|
+
state-transition logic without a test that was observed failing is not
|
|
80
|
+
accepted.
|
|
81
|
+
3. Implement the minimum that makes it pass. No drive-by refactoring.
|
|
82
|
+
4. Run `./scripts/verify.sh`.
|
|
83
|
+
5. Review your own diff, report, and stop before any git action.
|
|
84
|
+
|
|
85
|
+
Full workflow: [agents_docs/agent_workflow.md](agents_docs/agent_workflow.md).
|
|
86
|
+
|
|
87
|
+
## Where to read next
|
|
88
|
+
|
|
89
|
+
| Task | Read first |
|
|
90
|
+
|---|---|
|
|
91
|
+
| Add or change a block | [agents_docs/adding_a_block.md](agents_docs/adding_a_block.md) |
|
|
92
|
+
| Graph engine or validation | [agents_docs/graph_contracts.md](agents_docs/graph_contracts.md) |
|
|
93
|
+
| Exchanges, cache, or brokers | [agents_docs/exchanges_and_data.md](agents_docs/exchanges_and_data.md) |
|
|
94
|
+
| Safety or licensing | [agents_docs/invariants.md](agents_docs/invariants.md) |
|
|
95
|
+
| Everything else | [agents_docs/README.md](agents_docs/README.md) |
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). While the version is below 1.0, the public API may change in a minor release.
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.9.0] - 2026-07-30
|
|
10
|
+
|
|
11
|
+
First public release.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Typed dataflow strategy engine.** Strategies are JSON graphs of nodes across the FACT, STATE, POLICY, INTERPRETATION, and EXECUTION domains, with structural and entity validation.
|
|
16
|
+
- **Block catalogue** of 26 blocks — signals, filters, entries, exits, dynamic exits, and risk — compiled onto 35 typed nodes. Block helpers are pure functions over numpy with no framework dependency.
|
|
17
|
+
- **Pluggable backtest engine.** `BacktestEngineProtocol` plus discovery of independently distributed implementations through the `koval.backtest_engines` entry-point group, keeping this package MIT.
|
|
18
|
+
- **Paper broker** with a documented bracket/OCO fill ruleset and pessimistic resolution of ambiguous bars.
|
|
19
|
+
- **Non-production execution.** Binance Futures testnet supports fail-closed, market-entry-only execution with immediate bracket confirmation. WhiteBIT market data is read-only; execution is disabled because WhiteBIT has no verified public sandbox.
|
|
20
|
+
- **Market data adapters** for Binance and WhiteBIT (read-only REST) with a local Parquet OHLCV cache.
|
|
21
|
+
- **`koval` command-line interface** — `blocks`, `validate`, and `backtest`, the last against either a local CSV or fetched candles.
|
|
22
|
+
- **Runnable examples** with bundled synthetic OHLCV data, so the quickstart works offline and deterministically.
|
|
23
|
+
- **Typing.** The package ships a `py.typed` marker.
|
|
24
|
+
- **Version introspection.** `koval.__version__` reports the installed distribution version, read from distribution metadata so that `pyproject.toml` stays the only source of truth.
|
|
25
|
+
- **Agent-facing documentation.** A root `AGENTS.md` (read natively by most coding agents) with thin pointers for Claude Code, Gemini CLI, Cursor, and GitHub Copilot; a topic-per-file `agents_docs/` knowledge base; and `scripts/verify.sh`, the single command that reproduces CI. Cross-file consistency is pinned by `tests/test_agents_docs.py`.
|
|
26
|
+
|
|
27
|
+
### Security
|
|
28
|
+
|
|
29
|
+
- No code path reaches a real-money trading endpoint. Only `paper` and `binance_sandbox` are allowlisted execution modes; WhiteBIT execution fails closed. The invariant is pinned by `tests/safety/`.
|
|
30
|
+
- The MIT/GPL boundary is enforced by a test rather than by convention: no file in this package may import Backtrader.
|
|
31
|
+
- Releases are published to PyPI through Trusted Publishing (OIDC) with PEP 740 attestations. No long-lived PyPI credential is used in CI.
|
|
32
|
+
|
|
33
|
+
[Unreleased]: https://github.com/koval-finance/koval-engine/compare/v0.9.0...HEAD
|
|
34
|
+
[0.9.0]: https://github.com/koval-finance/koval-engine/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.
|