{"id":50223775,"url":"https://github.com/blechturm/ledgr","last_synced_at":"2026-06-06T02:10:07.086Z","repository":{"id":354159195,"uuid":"1119164147","full_name":"blechturm/ledgr","owner":"blechturm","description":"Deterministic, event-sourced EOD backtesting for R. Sealed market-data snapshots and an append-only trade ledger give every experiment a reproducible identity.","archived":false,"fork":false,"pushed_at":"2026-06-03T00:56:39.000Z","size":6362,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-03T01:12:46.472Z","etag":null,"topics":["backtesting","backtesting-frameworks","data-science","duckdb","reproducible-research","trading"],"latest_commit_sha":null,"homepage":"https://blechturm.github.io/ledgr/","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blechturm.png","metadata":{"files":{"readme":"README.Rmd","changelog":"NEWS.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-12-18T21:08:28.000Z","updated_at":"2026-06-03T00:56:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/blechturm/ledgr","commit_stats":null,"previous_names":["blechturm/ledgr"],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/blechturm/ledgr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blechturm%2Fledgr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blechturm%2Fledgr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blechturm%2Fledgr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blechturm%2Fledgr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blechturm","download_url":"https://codeload.github.com/blechturm/ledgr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blechturm%2Fledgr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33847265,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backtesting","backtesting-frameworks","data-science","duckdb","reproducible-research","trading"],"created_at":"2026-05-26T13:55:56.088Z","updated_at":"2026-06-03T04:00:42.910Z","avatar_url":"https://github.com/blechturm.png","language":"R","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\noutput:\n  github_document:\n    toc: false\n    html_preview: false\n    md_extensions: -smart\n---\n\n```{r setup, include=FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#\u003e\",\n  fig.path = \"man/figures/README-\",\n  out.width = \"100%\"\n)\noptions(width = 90)\noptions(cli.unicode = FALSE)\nif (file.exists(\"DESCRIPTION\") \u0026\u0026 requireNamespace(\"pkgload\", quietly = TRUE)) {\n  pkgload::load_all(\".\", quiet = TRUE)\n}\ndefault_output_hook \u003c- knitr::knit_hooks$get(\"output\")\nknitr::knit_hooks$set(\n  output = function(x, options) {\n    x \u003c- gsub(\"Database:(\\\\s+)[^\\\\r\\\\n]+[.]duckdb\", \"Database:\\\\1\u003ctemporary DuckDB path\u003e\", x, perl = TRUE)\n    x \u003c- gsub(\"[ \\t]+(?=\\n)\", \"\", x, perl = TRUE)\n    default_output_hook(x, options)\n  }\n)\n```\n\n# ledgr\n\n\u003cimg src=\"man/figures/logo.svg\" align=\"right\" alt=\"ledgr logo\" width=\"160\" class=\"ledgr-readme-logo\" /\u003e\n\nledgr is an event-sourced systematic trading research framework for R.\n\nUse it when you want a backtest result to be more than a temporary object in an\nR session. ledgr starts from sealed market-data snapshots, runs strategies\nthrough an experiment boundary, records event-sourced results, and lets you\nreopen the evidence later.\n\n```text\nsealed snapshot -\u003e experiment -\u003e run -\u003e event ledger -\u003e results\n```\n\nThe setup is not overhead. The setup is the audit trail.\n\n## Install\n\n```{r install, eval=FALSE}\nif (!requireNamespace(\"pak\", quietly = TRUE)) install.packages(\"pak\")\npak::pak(\"blechturm/ledgr\")\n```\n\n```{r attach, message=FALSE}\nlibrary(ledgr)\nlibrary(dplyr)\n\ndata(\"ledgr_demo_bars\", package = \"ledgr\")\n```\n\n## Run A Small Backtest\n\nStart with the package-owned demo bars. Real research should seal your own\nmarket data, but the demo data keeps this first run local and deterministic.\n\n```{r bars}\nbars \u003c- ledgr_demo_bars |\u003e\n  filter(\n    instrument_id %in% c(\"DEMO_01\", \"DEMO_02\"),\n    between(ts_utc, ledgr_utc(\"2019-01-01\"), ledgr_utc(\"2019-06-30\"))\n  )\n\nbars |\u003e\n  slice_head(n = 4)\n```\n\nSeal the bars, declare the strategy boundary, and run one parameter set.\n\n```{r quick-run}\nsnapshot \u003c- ledgr_snapshot_from_df(\n  bars,\n  snapshot_id = \"readme_demo\"\n)\n\nfeatures \u003c- ledgr_feature_map(\n  fast = ledgr_ind_sma(ledgr_param(\"fast_n\")),\n  slow = ledgr_ind_sma(ledgr_param(\"slow_n\"))\n)\n\nexp \u003c- ledgr_experiment(\n  snapshot = snapshot,\n  strategy = ledgr_demo_sma_crossover_strategy(),\n  features = features,\n  opening = ledgr_opening(cash = 10000)\n)\n\nbt \u003c- ledgr_run(\n  exp,\n  feature_params = list(fast_n = 10L, slow_n = 40L),\n  params = list(qty = 10, threshold = 0),\n  run_id = \"readme_sma_crossover\"\n)\n\nsummary(bt)\n```\n\n## Inspect The Evidence\n\nThe result views are derived from recorded events. The ledger is the source of\ntruth; trades, equity, and metrics are views over that evidence.\n\n```{r inspect}\nledgr_results(bt, what = \"trades\")\nhead(ledgr_results(bt, what = \"equity\"), 3)\n```\n\nStored strategy provenance is inspectable without rerunning or evaluating the\nstrategy source. Use `trust = FALSE` for source and metadata inspection.\n\n```{r extract-strategy}\nstored_strategy \u003c- ledgr_extract_strategy(snapshot, \"readme_sma_crossover\", trust = FALSE)\nlist(\n  reproducibility_level = stored_strategy$reproducibility_level,\n  hash_verified = stored_strategy$hash_verified,\n  strategy_params = stored_strategy$strategy_params\n)\n```\n\nHash verification proves stored-text identity, not code safety. Use\n`trust = TRUE` only when you already trust the store and intentionally want to\nrecover a function object.\n\n## Where To Go Next\n\n| Question | Article |\n| --- | --- |\n| I want the full research loop: snapshot, sweep, promotion, reopen. | [Research Workflow](https://blechturm.github.io/ledgr/articles/research-workflow.html) |\n| I want to write strategies correctly. | [Strategy Development](https://blechturm.github.io/ledgr/articles/strategy-development.html) |\n| I want feature maps, indicators, and active aliases. | [Indicators](https://blechturm.github.io/ledgr/articles/indicators.html) |\n| I want exploratory sweeps and candidate promotion. | [Sweeps](https://blechturm.github.io/ledgr/articles/sweeps.html) |\n| I want sealed snapshots, durable stores, backup, and reopen. | [Experiment Store](https://blechturm.github.io/ledgr/articles/experiment-store.html) |\n| I want hashes, provenance tiers, and limits of recovery. | [Reproducibility](https://blechturm.github.io/ledgr/articles/reproducibility.html) |\n| I want fills, trades, equity, metrics, and metric context. | [Metrics And Accounting](https://blechturm.github.io/ledgr/articles/metrics-and-accounting.html) |\n\nStart with the pkgdown site for the full article set:\n\u003chttps://blechturm.github.io/ledgr/\u003e.\n\nInstalled package help remains available from R:\n\n```{r docs, eval=FALSE}\nhelp(package = \"ledgr\")\nvignette(package = \"ledgr\")\n```\n\n## Ecosystem\n\nledgr connects to the R finance ecosystem through adapters. The core is narrow\nby design: `data -\u003e pulse -\u003e decision -\u003e fill -\u003e ledger event -\u003e portfolio\nstate`. Everything outside that sequence, such as data vendors, indicators,\ncharting, and analytics, can be provided by packages that already do those\nthings well.\n\n| ledgr owns | Other packages can own |\n|---|---|\n| sealed snapshots and hashes | market-data acquisition |\n| pulse construction and no-lookahead contexts | indicator calculations through adapters |\n| target validation, fills, and ledger events | charting and visualization |\n| run identity, provenance, and result reconstruction | downstream analytics and reporting |\n\nThis posture is deliberate. If you want an all-in-one charting or\narray-backtesting package, ledgr may not be the shortest path. Choose ledgr\nwhen you want the audit trail and adapter boundary to be explicit.\n\n## Scope\n\nThe current ledgr research API is experiment-first and includes sequential\nexploratory sweep support. It does not ship automatic ranking, `ledgr_tune()`,\nparallel sweep, walk-forward/PBO/CSCV helpers, full sweep artifact persistence,\nbroker adapters, paper trading, live trading, or short-selling semantics. Those\nare separate roadmap items with different state and safety requirements.\n\n`ledgr_run()` returns a live handle. The run artifacts are already durable when\nthe run finishes. Most result inspection opens and closes its own read\nconnection; explicit `close(bt)` is resource cleanup for long sessions,\nexplicit opens, and lazy result cursors.\n\n```{r cleanup, include=FALSE}\nclose(bt)\nledgr_snapshot_close(snapshot)\n```\n\n## Pre-CRAN Compatibility\n\nledgr is not yet on CRAN. Until the first CRAN release, stored artifacts,\ndatabase schemas, config hashes, provenance formats, and experimental APIs may\nchange without backward compatibility or a deprecation cycle. Treat pre-CRAN\nledgr as a research/development package and expect to rerun experiments after\nupgrading. Once ledgr is released on CRAN, the project will define an explicit\ncompatibility and deprecation policy.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblechturm%2Fledgr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblechturm%2Fledgr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblechturm%2Fledgr/lists"}