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.
Files changed (254) hide show
  1. koval_engine-0.9.0/.cursor/rules/koval-engine.mdc +9 -0
  2. koval_engine-0.9.0/.github/CODEOWNERS +2 -0
  3. koval_engine-0.9.0/.github/ISSUE_TEMPLATE/bug_report.yml +65 -0
  4. koval_engine-0.9.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  5. koval_engine-0.9.0/.github/ISSUE_TEMPLATE/feature_request.yml +42 -0
  6. koval_engine-0.9.0/.github/PULL_REQUEST_TEMPLATE.md +21 -0
  7. koval_engine-0.9.0/.github/copilot-instructions.md +5 -0
  8. koval_engine-0.9.0/.github/dependabot.yml +10 -0
  9. koval_engine-0.9.0/.github/workflows/ci.yml +57 -0
  10. koval_engine-0.9.0/.github/workflows/mirror.yml +31 -0
  11. koval_engine-0.9.0/.github/workflows/release.yml +115 -0
  12. koval_engine-0.9.0/.github/workflows/scorecard.yml +31 -0
  13. koval_engine-0.9.0/.gitignore +17 -0
  14. koval_engine-0.9.0/AGENTS.md +95 -0
  15. koval_engine-0.9.0/CHANGELOG.md +34 -0
  16. koval_engine-0.9.0/CLAUDE.md +9 -0
  17. koval_engine-0.9.0/CODE_OF_CONDUCT.md +132 -0
  18. koval_engine-0.9.0/CONTRIBUTING.md +88 -0
  19. koval_engine-0.9.0/GEMINI.md +6 -0
  20. koval_engine-0.9.0/LICENSE +21 -0
  21. koval_engine-0.9.0/MANIFEST.in +15 -0
  22. koval_engine-0.9.0/PKG-INFO +174 -0
  23. koval_engine-0.9.0/README.md +135 -0
  24. koval_engine-0.9.0/SECURITY.md +50 -0
  25. koval_engine-0.9.0/agents_docs/README.md +47 -0
  26. koval_engine-0.9.0/agents_docs/adding_a_block.md +42 -0
  27. koval_engine-0.9.0/agents_docs/agent_workflow.md +40 -0
  28. koval_engine-0.9.0/agents_docs/architecture.md +53 -0
  29. koval_engine-0.9.0/agents_docs/code_style.md +31 -0
  30. koval_engine-0.9.0/agents_docs/exchanges_and_data.md +42 -0
  31. koval_engine-0.9.0/agents_docs/glossary.md +46 -0
  32. koval_engine-0.9.0/agents_docs/graph_contracts.md +63 -0
  33. koval_engine-0.9.0/agents_docs/invariants.md +25 -0
  34. koval_engine-0.9.0/agents_docs/release_process.md +43 -0
  35. koval_engine-0.9.0/agents_docs/testing.md +61 -0
  36. koval_engine-0.9.0/agents_docs/troubleshooting.md +60 -0
  37. koval_engine-0.9.0/examples/generate_sample.py +60 -0
  38. koval_engine-0.9.0/examples/run_backtest.py +29 -0
  39. koval_engine-0.9.0/pyproject.toml +79 -0
  40. koval_engine-0.9.0/scripts/verify.sh +14 -0
  41. koval_engine-0.9.0/setup.cfg +4 -0
  42. koval_engine-0.9.0/src/koval/__init__.py +7 -0
  43. koval_engine-0.9.0/src/koval/_version.py +7 -0
  44. koval_engine-0.9.0/src/koval/cli/__init__.py +7 -0
  45. koval_engine-0.9.0/src/koval/cli/data.py +27 -0
  46. koval_engine-0.9.0/src/koval/cli/main.py +239 -0
  47. koval_engine-0.9.0/src/koval/engine/__init__.py +0 -0
  48. koval_engine-0.9.0/src/koval/engine/account_state.py +105 -0
  49. koval_engine-0.9.0/src/koval/engine/backtest_engine.py +114 -0
  50. koval_engine-0.9.0/src/koval/engine/broker.py +151 -0
  51. koval_engine-0.9.0/src/koval/engine/client_order_id.py +22 -0
  52. koval_engine-0.9.0/src/koval/engine/engine_events.py +25 -0
  53. koval_engine-0.9.0/src/koval/engine/execution_settings.py +170 -0
  54. koval_engine-0.9.0/src/koval/engine/live_engine.py +989 -0
  55. koval_engine-0.9.0/src/koval/engine/live_feed.py +216 -0
  56. koval_engine-0.9.0/src/koval/engine/logger.py +146 -0
  57. koval_engine-0.9.0/src/koval/engine/paper_broker.py +544 -0
  58. koval_engine-0.9.0/src/koval/engine/time_range.py +11 -0
  59. koval_engine-0.9.0/src/koval/engine/timeframe_utils.py +29 -0
  60. koval_engine-0.9.0/src/koval/engine/trade_context.py +46 -0
  61. koval_engine-0.9.0/src/koval/engine/trade_indicators.py +169 -0
  62. koval_engine-0.9.0/src/koval/engine/trade_metrics.py +50 -0
  63. koval_engine-0.9.0/src/koval/engine/trade_narrator.py +27 -0
  64. koval_engine-0.9.0/src/koval/engine/venue_metadata.py +164 -0
  65. koval_engine-0.9.0/src/koval/examples/__init__.py +25 -0
  66. koval_engine-0.9.0/src/koval/examples/data/README.md +5 -0
  67. koval_engine-0.9.0/src/koval/examples/data/sample-1h.csv +1201 -0
  68. koval_engine-0.9.0/src/koval/examples/graphs/ema_cross_trend.json +21 -0
  69. koval_engine-0.9.0/src/koval/exchanges/__init__.py +47 -0
  70. koval_engine-0.9.0/src/koval/exchanges/auth.py +76 -0
  71. koval_engine-0.9.0/src/koval/exchanges/base.py +180 -0
  72. koval_engine-0.9.0/src/koval/exchanges/binance.py +148 -0
  73. koval_engine-0.9.0/src/koval/exchanges/binance_sandbox.py +901 -0
  74. koval_engine-0.9.0/src/koval/exchanges/ohlcv_cache.py +221 -0
  75. koval_engine-0.9.0/src/koval/exchanges/sandbox_factory.py +39 -0
  76. koval_engine-0.9.0/src/koval/exchanges/whitebit.py +153 -0
  77. koval_engine-0.9.0/src/koval/exchanges/whitebit_sandbox.py +35 -0
  78. koval_engine-0.9.0/src/koval/py.typed +1 -0
  79. koval_engine-0.9.0/src/koval/strategy/__init__.py +0 -0
  80. koval_engine-0.9.0/src/koval/strategy/base/__init__.py +0 -0
  81. koval_engine-0.9.0/src/koval/strategy/base/declarative.py +110 -0
  82. koval_engine-0.9.0/src/koval/strategy/base/trade_setup.py +52 -0
  83. koval_engine-0.9.0/src/koval/strategy/block_assembler.py +62 -0
  84. koval_engine-0.9.0/src/koval/strategy/graph/__init__.py +0 -0
  85. koval_engine-0.9.0/src/koval/strategy/graph/compat.py +280 -0
  86. koval_engine-0.9.0/src/koval/strategy/graph/domains.py +40 -0
  87. koval_engine-0.9.0/src/koval/strategy/graph/entities.py +108 -0
  88. koval_engine-0.9.0/src/koval/strategy/graph/executor.py +144 -0
  89. koval_engine-0.9.0/src/koval/strategy/graph/node.py +82 -0
  90. koval_engine-0.9.0/src/koval/strategy/graph/ports.py +24 -0
  91. koval_engine-0.9.0/src/koval/strategy/graph/registry.py +44 -0
  92. koval_engine-0.9.0/src/koval/strategy/graph/state_store.py +17 -0
  93. koval_engine-0.9.0/src/koval/strategy/graph/strategy.py +159 -0
  94. koval_engine-0.9.0/src/koval/strategy/graph/validation.py +141 -0
  95. koval_engine-0.9.0/src/koval/strategy/helpers/__init__.py +0 -0
  96. koval_engine-0.9.0/src/koval/strategy/helpers/_math.py +132 -0
  97. koval_engine-0.9.0/src/koval/strategy/helpers/exits/__init__.py +0 -0
  98. koval_engine-0.9.0/src/koval/strategy/helpers/exits/breakeven.py +25 -0
  99. koval_engine-0.9.0/src/koval/strategy/helpers/exits/fixed.py +27 -0
  100. koval_engine-0.9.0/src/koval/strategy/helpers/exits/pricing.py +42 -0
  101. koval_engine-0.9.0/src/koval/strategy/helpers/exits/trailing.py +22 -0
  102. koval_engine-0.9.0/src/koval/strategy/helpers/filters/__init__.py +0 -0
  103. koval_engine-0.9.0/src/koval/strategy/helpers/filters/momentum.py +55 -0
  104. koval_engine-0.9.0/src/koval/strategy/helpers/filters/trend.py +83 -0
  105. koval_engine-0.9.0/src/koval/strategy/helpers/filters/volatility.py +42 -0
  106. koval_engine-0.9.0/src/koval/strategy/helpers/interp/__init__.py +0 -0
  107. koval_engine-0.9.0/src/koval/strategy/helpers/interp/scoring.py +28 -0
  108. koval_engine-0.9.0/src/koval/strategy/helpers/risk/__init__.py +0 -0
  109. koval_engine-0.9.0/src/koval/strategy/helpers/risk/gates.py +55 -0
  110. koval_engine-0.9.0/src/koval/strategy/helpers/risk/position_sizer.py +67 -0
  111. koval_engine-0.9.0/src/koval/strategy/helpers/risk/sizing.py +15 -0
  112. koval_engine-0.9.0/src/koval/strategy/helpers/signals/__init__.py +0 -0
  113. koval_engine-0.9.0/src/koval/strategy/helpers/signals/candlesticks.py +74 -0
  114. koval_engine-0.9.0/src/koval/strategy/helpers/signals/smc.py +110 -0
  115. koval_engine-0.9.0/src/koval/strategy/helpers/signals/technical.py +52 -0
  116. koval_engine-0.9.0/src/koval/strategy/nodes/__init__.py +12 -0
  117. koval_engine-0.9.0/src/koval/strategy/nodes/aggregator.py +186 -0
  118. koval_engine-0.9.0/src/koval/strategy/nodes/exec_pipeline.py +372 -0
  119. koval_engine-0.9.0/src/koval/strategy/nodes/execution.py +93 -0
  120. koval_engine-0.9.0/src/koval/strategy/nodes/fact.py +376 -0
  121. koval_engine-0.9.0/src/koval/strategy/nodes/interp.py +120 -0
  122. koval_engine-0.9.0/src/koval/strategy/nodes/policy.py +233 -0
  123. koval_engine-0.9.0/src/koval/strategy/nodes/scoring.py +276 -0
  124. koval_engine-0.9.0/src/koval/strategy/nodes/state.py +116 -0
  125. koval_engine-0.9.0/src/koval/strategy/presets/__init__.py +8 -0
  126. koval_engine-0.9.0/src/koval/strategy/presets/risk_pipeline_demo.py +52 -0
  127. koval_engine-0.9.0/src/koval/strategy/presets/sweep_choch_reversal.py +73 -0
  128. koval_engine-0.9.0/src/koval/strategy/promotion_gates.py +112 -0
  129. koval_engine-0.9.0/src/koval/strategy/registry.py +778 -0
  130. koval_engine-0.9.0/src/koval/strategy/schemas.py +225 -0
  131. koval_engine-0.9.0/src/koval_engine.egg-info/PKG-INFO +174 -0
  132. koval_engine-0.9.0/src/koval_engine.egg-info/SOURCES.txt +252 -0
  133. koval_engine-0.9.0/src/koval_engine.egg-info/dependency_links.txt +1 -0
  134. koval_engine-0.9.0/src/koval_engine.egg-info/entry_points.txt +2 -0
  135. koval_engine-0.9.0/src/koval_engine.egg-info/requires.txt +16 -0
  136. koval_engine-0.9.0/src/koval_engine.egg-info/top_level.txt +1 -0
  137. koval_engine-0.9.0/tests/__init__.py +0 -0
  138. koval_engine-0.9.0/tests/cli/__init__.py +0 -0
  139. koval_engine-0.9.0/tests/cli/conftest.py +26 -0
  140. koval_engine-0.9.0/tests/cli/test_cli_backtest_bad_engine.py +36 -0
  141. koval_engine-0.9.0/tests/cli/test_cli_backtest_fetch.py +98 -0
  142. koval_engine-0.9.0/tests/cli/test_cli_backtest_no_engine.py +30 -0
  143. koval_engine-0.9.0/tests/cli/test_cli_backtest_offline.py +25 -0
  144. koval_engine-0.9.0/tests/cli/test_cli_blocks.py +22 -0
  145. koval_engine-0.9.0/tests/cli/test_cli_data.py +50 -0
  146. koval_engine-0.9.0/tests/cli/test_cli_examples.py +62 -0
  147. koval_engine-0.9.0/tests/cli/test_cli_validate.py +47 -0
  148. koval_engine-0.9.0/tests/conftest.py +3 -0
  149. koval_engine-0.9.0/tests/engine/__init__.py +0 -0
  150. koval_engine-0.9.0/tests/engine/live_fixtures.py +51 -0
  151. koval_engine-0.9.0/tests/engine/test_account_state.py +75 -0
  152. koval_engine-0.9.0/tests/engine/test_backtest_engine.py +47 -0
  153. koval_engine-0.9.0/tests/engine/test_broker.py +122 -0
  154. koval_engine-0.9.0/tests/engine/test_client_order_id.py +45 -0
  155. koval_engine-0.9.0/tests/engine/test_engine_events.py +63 -0
  156. koval_engine-0.9.0/tests/engine/test_engine_loader.py +60 -0
  157. koval_engine-0.9.0/tests/engine/test_execution_settings.py +124 -0
  158. koval_engine-0.9.0/tests/engine/test_live_engine.py +1273 -0
  159. koval_engine-0.9.0/tests/engine/test_live_feed.py +190 -0
  160. koval_engine-0.9.0/tests/engine/test_live_parity.py +53 -0
  161. koval_engine-0.9.0/tests/engine/test_logger.py +100 -0
  162. koval_engine-0.9.0/tests/engine/test_paper_broker.py +526 -0
  163. koval_engine-0.9.0/tests/engine/test_protocol_version.py +26 -0
  164. koval_engine-0.9.0/tests/engine/test_time_range.py +16 -0
  165. koval_engine-0.9.0/tests/engine/test_timeframe_utils.py +40 -0
  166. koval_engine-0.9.0/tests/engine/test_trade_context.py +35 -0
  167. koval_engine-0.9.0/tests/engine/test_trade_indicators.py +119 -0
  168. koval_engine-0.9.0/tests/engine/test_trade_metrics.py +66 -0
  169. koval_engine-0.9.0/tests/engine/test_trade_narrator.py +32 -0
  170. koval_engine-0.9.0/tests/engine/test_venue_metadata.py +207 -0
  171. koval_engine-0.9.0/tests/exchanges/__init__.py +0 -0
  172. koval_engine-0.9.0/tests/exchanges/conftest.py +40 -0
  173. koval_engine-0.9.0/tests/exchanges/test_auth.py +56 -0
  174. koval_engine-0.9.0/tests/exchanges/test_base.py +76 -0
  175. koval_engine-0.9.0/tests/exchanges/test_binance.py +236 -0
  176. koval_engine-0.9.0/tests/exchanges/test_binance_sandbox.py +1173 -0
  177. koval_engine-0.9.0/tests/exchanges/test_exchange_factory.py +26 -0
  178. koval_engine-0.9.0/tests/exchanges/test_ohlcv_cache.py +469 -0
  179. koval_engine-0.9.0/tests/exchanges/test_sandbox_factory.py +40 -0
  180. koval_engine-0.9.0/tests/exchanges/test_whitebit.py +211 -0
  181. koval_engine-0.9.0/tests/exchanges/test_whitebit_sandbox.py +32 -0
  182. koval_engine-0.9.0/tests/safety/__init__.py +0 -0
  183. koval_engine-0.9.0/tests/safety/test_no_real_money_path.py +128 -0
  184. koval_engine-0.9.0/tests/smoke/test_binance_sandbox_manual.py +52 -0
  185. koval_engine-0.9.0/tests/strategy/__init__.py +0 -0
  186. koval_engine-0.9.0/tests/strategy/graph/__init__.py +0 -0
  187. koval_engine-0.9.0/tests/strategy/graph/test_barcontext_account.py +14 -0
  188. koval_engine-0.9.0/tests/strategy/graph/test_compat.py +62 -0
  189. koval_engine-0.9.0/tests/strategy/graph/test_compat_golden.py +45 -0
  190. koval_engine-0.9.0/tests/strategy/graph/test_domains.py +23 -0
  191. koval_engine-0.9.0/tests/strategy/graph/test_dynamic_exit.py +84 -0
  192. koval_engine-0.9.0/tests/strategy/graph/test_entities.py +96 -0
  193. koval_engine-0.9.0/tests/strategy/graph/test_executor.py +292 -0
  194. koval_engine-0.9.0/tests/strategy/graph/test_graph_strategy.py +141 -0
  195. koval_engine-0.9.0/tests/strategy/graph/test_graph_strategy_blocked.py +92 -0
  196. koval_engine-0.9.0/tests/strategy/graph/test_interp_chain.py +212 -0
  197. koval_engine-0.9.0/tests/strategy/graph/test_interp_full_engine_golden.py +163 -0
  198. koval_engine-0.9.0/tests/strategy/graph/test_ports.py +30 -0
  199. koval_engine-0.9.0/tests/strategy/graph/test_reasoning_surfacing.py +98 -0
  200. koval_engine-0.9.0/tests/strategy/graph/test_registry.py +91 -0
  201. koval_engine-0.9.0/tests/strategy/graph/test_risk_pipeline_golden.py +166 -0
  202. koval_engine-0.9.0/tests/strategy/graph/test_state_store.py +21 -0
  203. koval_engine-0.9.0/tests/strategy/graph/test_validation.py +221 -0
  204. koval_engine-0.9.0/tests/strategy/graph/test_validation_cycle.py +9 -0
  205. koval_engine-0.9.0/tests/strategy/helpers/__init__.py +0 -0
  206. koval_engine-0.9.0/tests/strategy/helpers/exits/__init__.py +0 -0
  207. koval_engine-0.9.0/tests/strategy/helpers/exits/test_breakeven.py +83 -0
  208. koval_engine-0.9.0/tests/strategy/helpers/exits/test_fixed.py +45 -0
  209. koval_engine-0.9.0/tests/strategy/helpers/exits/test_pricing.py +40 -0
  210. koval_engine-0.9.0/tests/strategy/helpers/exits/test_trailing.py +79 -0
  211. koval_engine-0.9.0/tests/strategy/helpers/filters/__init__.py +0 -0
  212. koval_engine-0.9.0/tests/strategy/helpers/filters/test_momentum.py +111 -0
  213. koval_engine-0.9.0/tests/strategy/helpers/filters/test_trend.py +54 -0
  214. koval_engine-0.9.0/tests/strategy/helpers/filters/test_volatility.py +54 -0
  215. koval_engine-0.9.0/tests/strategy/helpers/interp/__init__.py +0 -0
  216. koval_engine-0.9.0/tests/strategy/helpers/interp/test_scoring.py +26 -0
  217. koval_engine-0.9.0/tests/strategy/helpers/risk/__init__.py +0 -0
  218. koval_engine-0.9.0/tests/strategy/helpers/risk/test_gates.py +118 -0
  219. koval_engine-0.9.0/tests/strategy/helpers/risk/test_position_sizer.py +186 -0
  220. koval_engine-0.9.0/tests/strategy/helpers/risk/test_sizing.py +24 -0
  221. koval_engine-0.9.0/tests/strategy/helpers/signals/__init__.py +0 -0
  222. koval_engine-0.9.0/tests/strategy/helpers/signals/test_candlesticks.py +114 -0
  223. koval_engine-0.9.0/tests/strategy/helpers/signals/test_smc.py +122 -0
  224. koval_engine-0.9.0/tests/strategy/helpers/signals/test_technical.py +72 -0
  225. koval_engine-0.9.0/tests/strategy/helpers/test_math.py +110 -0
  226. koval_engine-0.9.0/tests/strategy/nodes/__init__.py +0 -0
  227. koval_engine-0.9.0/tests/strategy/nodes/test_aggregator.py +192 -0
  228. koval_engine-0.9.0/tests/strategy/nodes/test_execution_nodes.py +340 -0
  229. koval_engine-0.9.0/tests/strategy/nodes/test_fact_nodes.py +72 -0
  230. koval_engine-0.9.0/tests/strategy/nodes/test_interp_nodes.py +63 -0
  231. koval_engine-0.9.0/tests/strategy/nodes/test_policy_nodes.py +38 -0
  232. koval_engine-0.9.0/tests/strategy/nodes/test_scoring_nodes.py +276 -0
  233. koval_engine-0.9.0/tests/strategy/nodes/test_state_nodes.py +45 -0
  234. koval_engine-0.9.0/tests/strategy/presets/__init__.py +0 -0
  235. koval_engine-0.9.0/tests/strategy/presets/test_risk_pipeline_demo.py +8 -0
  236. koval_engine-0.9.0/tests/strategy/presets/test_sweep_choch_reversal.py +48 -0
  237. koval_engine-0.9.0/tests/strategy/test_block_assembler.py +331 -0
  238. koval_engine-0.9.0/tests/strategy/test_declarative.py +175 -0
  239. koval_engine-0.9.0/tests/strategy/test_promotion_gates.py +129 -0
  240. koval_engine-0.9.0/tests/strategy/test_registry_blocks.py +365 -0
  241. koval_engine-0.9.0/tests/strategy/test_registry_strategies.py +126 -0
  242. koval_engine-0.9.0/tests/strategy/test_schemas.py +122 -0
  243. koval_engine-0.9.0/tests/strategy/test_trade_setup.py +199 -0
  244. koval_engine-0.9.0/tests/test_agents_docs.py +96 -0
  245. koval_engine-0.9.0/tests/test_example_data.py +58 -0
  246. koval_engine-0.9.0/tests/test_license_boundary.py +79 -0
  247. koval_engine-0.9.0/tests/test_package_metadata.py +29 -0
  248. koval_engine-0.9.0/tests/test_public_language.py +125 -0
  249. koval_engine-0.9.0/tests/test_public_surface.py +99 -0
  250. koval_engine-0.9.0/tests/test_readme_quickstart.py +83 -0
  251. koval_engine-0.9.0/tests/test_release_docs.py +69 -0
  252. koval_engine-0.9.0/tests/test_release_workflow.py +65 -0
  253. koval_engine-0.9.0/tests/test_sdist_contents.py +118 -0
  254. 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,2 @@
1
+ # Default owner for everything in this repository.
2
+ * @rostredko
@@ -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,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Report a security vulnerability
4
+ url: https://github.com/koval-finance/koval-engine/security/advisories/new
5
+ about: Report privately through GitHub. Never open a public issue for a security problem.
@@ -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,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 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.