{"id":23133905,"url":"https://github.com/simongarisch/pxtrade","last_synced_at":"2026-02-11T18:02:55.836Z","repository":{"id":55521352,"uuid":"293418866","full_name":"simongarisch/pxtrade","owner":"simongarisch","description":"A multi currency, event driven backtester written in Python.","archived":false,"fork":false,"pushed_at":"2021-03-01T02:55:55.000Z","size":5015,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-08T23:45:17.052Z","etag":null,"topics":["backtest","bitcoin","event","fx","python","stock","trade","trading"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simongarisch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-09-07T04:08:11.000Z","updated_at":"2021-11-08T10:45:24.000Z","dependencies_parsed_at":"2022-08-15T02:20:29.288Z","dependency_job_id":null,"html_url":"https://github.com/simongarisch/pxtrade","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/simongarisch/pxtrade","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simongarisch%2Fpxtrade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simongarisch%2Fpxtrade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simongarisch%2Fpxtrade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simongarisch%2Fpxtrade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simongarisch","download_url":"https://codeload.github.com/simongarisch/pxtrade/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simongarisch%2Fpxtrade/sbom","scorecard":{"id":824797,"data":{"date":"2025-08-11","repo":{"name":"github.com/simongarisch/pxtrade","commit":"6245c0a47017a880299fa7704a49580f394fa87b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.7,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":7,"reason":"3 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2024-48 / GHSA-fj7x-q9j7-g6q6","Warn: Project is vulnerable to: GHSA-29gw-9793-fvw7","Warn: Project is vulnerable to: PYSEC-2022-12 / GHSA-pq7m-3gw7-gq5x"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T16:25:28.108Z","repository_id":55521352,"created_at":"2025-08-23T16:25:28.108Z","updated_at":"2025-08-23T16:25:28.108Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29340394,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-11T16:14:43.024Z","status":"ssl_error","status_checked_at":"2026-02-11T16:14:15.258Z","response_time":97,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["backtest","bitcoin","event","fx","python","stock","trade","trading"],"created_at":"2024-12-17T12:08:43.786Z","updated_at":"2026-02-11T18:02:55.794Z","avatar_url":"https://github.com/simongarisch.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"## pxtrade\n[![Python](https://img.shields.io/badge/python-v3-brightgreen.svg)](https://www.python.org/)\n[![Build Status](https://travis-ci.org/simongarisch/pxtrade.svg?branch=master)](https://travis-ci.org/simongarisch/pxtrade)\n[![Coverage Status](https://coveralls.io/repos/github/simongarisch/pxtrade/badge.svg)](https://coveralls.io/github/simongarisch/pxtrade?branch=master)\n[![PyPI version](https://badge.fury.io/py/pxtrade.svg)](https://badge.fury.io/py/pxtrade)\n[![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)\n[![Codestyle](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![Maintainability](https://api.codeclimate.com/v1/badges/22d56bf02ecbd8ccea22/maintainability)](https://codeclimate.com/github/simongarisch/pxtrade/maintainability)\n\nA multi currency, event driven backtester written in Python.\n\n\n### Installation\n```bash\npip install pxtrade\n```\n\n### Examples\n[Notebooks](https://github.com/simongarisch/pxtrade/tree/master/notes) are available to cover the main concepts and examples.\n-  [equities buy and hold](https://github.com/simongarisch/pxtrade/blob/master/notes/06%20Example%20-%20Buy%20And%20Hold.ipynb)\n-  [fx trading](https://github.com/simongarisch/pxtrade/blob/master/notes/08%20Example%20-%20FX.ipynb)\n-  [bitcoin](https://github.com/simongarisch/pxtrade/blob/master/notes/09%20Example%20-%20Bitcoin.ipynb)\n-  [Intraday trading](https://github.com/simongarisch/pxtrade/blob/master/notes/11%20Example%20-%20FX%20Intraday%20with%20Benchmark.ipynb)\n\n### Assets and Portfolios\nBefore we can run a backtest we need to define the assets and portfolios involved.\n```python\nfrom pxtrade.assets import reset, Cash, Stock, FxRate, Portfolio\n\n\nreset()\naud = Cash(\"AUD\")\nusd = Cash(\"USD\")\naudusd = FxRate(\"AUDUSD\")\nspy = Stock(\"SPY\")\nportfolio = Portfolio(\"USD\", code=\"Portfolio\")  # a portfolio denominated in USD\nbenchmark = Portfolio(\"USD\", code=\"Benchmark\")\n\nprint(portfolio)\n```\nPortfolio('USD')\n    \n\n\n```python\nportfolio.transfer(usd, 1e6)  # start both with 1M USD\nbenchmark.transfer(usd, 1e6)\n\nprint(portfolio)\n```\nPortfolio('USD'):\nCash('USD', 1.0, currency_code='USD'): 1,000,000\n    \n\n```python\nportfolio.value\n```\n1000000.0\n\n\n\n### Imposing portfolio constraints through compliance\nIdeally there will be risk limits in place when running a backtest. Some concrete compliance rules are provided, but you can also define your own by [inheriting from ComplianceRule](https://github.com/simongarisch/pxtrade/blob/master/notes/02%20The%20Trade%20Lifecycle.ipynb).\n\n```python\nfrom pxtrade.compliance import Compliance, UnitLimit\n\n\nfor port in [portfolio, benchmark]:\n    port.compliance = Compliance().add_rule(\n        UnitLimit(spy, 1000)\n    )\n```\n\n### Defining a portfolio broker\nDifferent portfolios / strategies are likely to vary materially in broker charges. All portfolios have a default broker that executes trades at the last price with no charge (or slippage). Brokers have separate execution and charges strategies. You can use the classes available or define custom strategies by inheriting from  [AbstractExecution](https://github.com/simongarisch/pxtrade/blob/master/pxtrade/broker/execution.py#L6) or [AbstractCharges](https://github.com/simongarisch/pxtrade/blob/master/pxtrade/broker/charges.py#L8). Note that backtesting supports multiple currencies. The portfolio could be denominated in USD, for example, but broker charges defined in AUD terms.\n\n\n```python\nfrom pxtrade.broker import (\n    Broker, \n    FillAtLastWithSlippage,\n    FixedRatePlusPercentage,\n)\n\n\nportfolio.broker = Broker(\n    execution_strategy=FillAtLastWithSlippage(0),  # no slippage, just fill at last\n    charges_strategy=FixedRatePlusPercentage(20, 0, currency_code=\"AUD\")  # fixed charge of AUD 20 per trade.\n)\n```\n\n### Defining a trading strategy\nAll strategy classes must inherit from pxtrade.Strategy and implement a generate_trades method. Note that the trades returned can either be None, a trade instance or list of trades.\n\n```python\nfrom pxtrade import Strategy, Trade \n\n\nclass ExampleStrategy(Strategy):\n    def generate_trades(self):\n        trades = list()\n\n        # get the portfolio trades first\n        if spy.price \u003c 330:\n            trades.append(Trade(portfolio, spy, +100))\n\n        trades.append(Trade(benchmark, spy, +1000))\n\n        return trades\n```\n\n### The backtest instance and trade history\nA backtest takes a strategy instance as its argument. Any instances of History then record state through time as events are processed.\n\n```python\nfrom pxtrade import Backtest, History\n\n\nbacktest = Backtest(ExampleStrategy())\n\nhistory = History(\n    portfolios=[portfolio, benchmark],\n    backtest=backtest\n)\n```\n\n### [Loading event data](https://github.com/simongarisch/pxtrade/blob/master/notes/05%20Bulk%20Event%20Loads.ipynb)\nEvents can be loaded either from yahoo finance or from an existing data frame.\n\n```python\nfrom datetime import date\nfrom pxtrade.events.yahoo import load_yahoo_prices\n\n\nstart_date = date(2020, 6, 30)\nend_date = date(2020, 9, 30)\n\nload_yahoo_prices(\n    [spy, audusd], backtest,\n    start_date=start_date,\n    end_date=end_date,\n)\n```\n\n### Running the backtest and collecting history\n\n```python\nbacktest.run()\n\ndf = history.get()\n```\n\n```python\ndf.columns\n```\n    Index(['AUD', 'AUDUSD', 'Benchmark', 'Benchmark_AUD', 'Benchmark_SPY',\n           'Benchmark_USD', 'Portfolio', 'Portfolio_AUD', 'Portfolio_SPY',\n           'Portfolio_USD', 'SPY', 'USD'],\n          dtype='object')\n\n```python\nimport cufflinks as cf\n\n\ncolumns = [\"Portfolio_SPY\", \"Benchmark_SPY\", \"SPY\"]\ndf[columns].iplot(\n    secondary_y=\"SPY\",\n    title=\"Portfolio Holdings of SPY\",\n)\n```\n![holdings](https://github.com/simongarisch/pxtrade/blob/master/notes/portfolio_holdings_of_spy.png?raw=true)\n\n\n```python\ncolumns = [\"Portfolio\", \"Benchmark\"]\ndf[columns].iplot(\n    title=\"Portfolio Value\",\n)\n```\n![holdings](https://github.com/simongarisch/pxtrade/blob/master/notes/portfolio_value.png?raw=true)\n\n***\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimongarisch%2Fpxtrade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimongarisch%2Fpxtrade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimongarisch%2Fpxtrade/lists"}