zipfolio 0.1.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.
@@ -0,0 +1,27 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 -- 2026-10-13
4
+
5
+ First release, extracted from the ZipLime backtester, where it builds the
6
+ report next to the QuantStats tearsheet of every backtest.
7
+
8
+ - `build_tearsheet`: one self-contained HTML page in the QuantStats Pro look --
9
+ Performance, Positions, Instruments, Sector Analysis, Factor Analysis,
10
+ Portfolio Risk, Transactions, Execution, Trading Costs, Round Trips, Capacity.
11
+ - `zipfolio.ziplime`: daily bars, per-fill bars and decision prices, and order
12
+ types read from a ziplime run.
13
+ - Fama-French 3/5 factors and momentum, daily, from Kenneth French's data
14
+ library, cached for a week.
15
+ - GICS sectors for US tickers from a table the user supplies (`table=` or
16
+ `ZIPFOLIO_GICS_TABLE`); `scripts/build_us_sector_map.py` builds one. No
17
+ sector data ships with the package -- GICS is licensed by MSCI and S&P.
18
+ - Every report links to https://github.com/Limex-com/zipfolio in its header
19
+ and footer, next to the Zipfolio version that built it, under the title
20
+ "Zipfolio Tearsheet: Portfolio, Execution & Cost Analysis".
21
+ - Fixes to pyfolio-reloaded 0.9.9 behaviour, applied without patching it
22
+ globally: the capacity join on same-day fills, the New-York-only fill-time
23
+ chart, the exposure panel lost to pandas period axes, overlapping labels.
24
+ - Allocation charts (top positions, sectors) draw a weight only while it is
25
+ held: an unheld name is a gap, not a zero, so exits and entries are no
26
+ longer vertical drops to the axis; one-session holdings are dotted, and the
27
+ axis keeps zero.
zipfolio-0.1.0/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
@@ -0,0 +1,316 @@
1
+ Metadata-Version: 2.4
2
+ Name: zipfolio
3
+ Version: 0.1.0
4
+ Summary: Backtest tearsheets that read the book, not just the returns: positions, instruments, sectors, factors, execution realism and trading costs. Part of the ZipLime ecosystem.
5
+ License-Expression: Apache-2.0
6
+ License-File: LICENSE
7
+ Keywords: backtesting,tearsheet,pyfolio,ziplime,portfolio-analytics,execution,fama-french
8
+ Author: Ziplime
9
+ Requires-Python: >=3.10
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Financial and Insurance Industry
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Topic :: Office/Business :: Financial :: Investment
14
+ Classifier: Programming Language :: Python :: 3
15
+ Provides-Extra: all
16
+ Provides-Extra: risk
17
+ Provides-Extra: ziplime
18
+ Requires-Dist: cycler (>=0.11)
19
+ Requires-Dist: empyrical-reloaded (>=0.5.9)
20
+ Requires-Dist: matplotlib (>=3.8)
21
+ Requires-Dist: numpy (>=1.26)
22
+ Requires-Dist: pandas (>=2.1,<3)
23
+ Requires-Dist: polars (>=1.0) ; extra == "all"
24
+ Requires-Dist: polars (>=1.0) ; extra == "ziplime"
25
+ Requires-Dist: pyfolio-reloaded (>=0.9.9)
26
+ Requires-Dist: scipy (>=1.11)
27
+ Requires-Dist: seaborn (>=0.13)
28
+ Requires-Dist: skfolio (>=0.15) ; extra == "all"
29
+ Requires-Dist: skfolio (>=0.15) ; extra == "risk"
30
+ Requires-Dist: statsmodels (>=0.14)
31
+ Project-URL: Changelog, https://github.com/Limex-com/zipfolio/blob/main/CHANGELOG.md
32
+ Project-URL: Homepage, https://github.com/Limex-com/zipfolio
33
+ Project-URL: Issues, https://github.com/Limex-com/zipfolio/issues
34
+ Project-URL: Repository, https://github.com/Limex-com/zipfolio
35
+ Description-Content-Type: text/markdown
36
+
37
+ # Zipfolio
38
+
39
+ **Backtest tearsheets that read the book, not just the returns.**
40
+
41
+ Zipfolio turns a backtest into one self-contained HTML report about *how the
42
+ strategy behaves position by position*: what it held and how concentrated it
43
+ was, what each instrument and sector earned, which factors it was really
44
+ exposed to, where its risk sat, how its orders were filled -- and how far those
45
+ fills can be believed -- and what trading costs took. It is part of the
46
+ [ZipLime](https://github.com/Limex-com) ecosystem, where it is built for every
47
+ backtest next to the QuantStats returns tearsheet.
48
+
49
+ ```python
50
+ from zipfolio import build_tearsheet
51
+
52
+ build_tearsheet("report.html", returns, benchmark,
53
+ position_records=positions, cash=ending_cash, transactions=fills,
54
+ orders=orders, fill_bars=fill_bars, decision_prices=decisions,
55
+ market_data=daily_bars, cost_settings=settings)
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Why a backtester-aware report
61
+
62
+ A returns tearsheet -- QuantStats, or pyfolio fed only a return series -- sees
63
+ one number per day. That is enough for Sharpe ratios and drawdowns, and nothing
64
+ else: it cannot tell you whether a fill was possible, what slippage cost, or
65
+ which position carried the risk, because none of that is in the returns.
66
+
67
+ A backtester knows all of it while it runs. Every order has a type, a creation
68
+ time, a limit or a stop; every fill belongs to an order and happens on a bar
69
+ with an open, high, low, close and volume; every cost comes from a model with
70
+ known settings. Most of this is thrown away once the simulation ends.
71
+ **Zipfolio is built to be fed by the backtester itself**, while that detail
72
+ still exists, and that is what makes its metrics possible:
73
+
74
+ | Question the report answers | What it needs | Where a ziplime run has it |
75
+ | --- | --- | --- |
76
+ | Was each fill priced inside the bar it happened on? | the fill's own bar (OHLC) | the market-data bundle, joined as of the fill time |
77
+ | Did a fill take more of the bar's volume than could trade? | the fill's bar volume | the same bundle |
78
+ | Did the strategy trade at a price it had only just seen? | execution timing settings | `same_bar_execution`, `price_used_in_order_execution` |
79
+ | What did a fill cost over the price the strategy decided at? | the close at the order's creation | the order's `created` time, joined to the bundle |
80
+ | How long did orders wait; were any left unfilled, and why? | order lifecycle | orders: `created`, `dt`, `filled`, `status`, `reason` |
81
+ | Which order types did the strategy use? | execution style | `MarketOrder` / `LimitOrder` / `StopOrder` / `StopLimitOrder` |
82
+ | What did commission cost? | commission per order | `order.commission` (ziplime charges it to the order, not the fill) |
83
+ | What did slippage cost? | the slippage model | `FixedBasisPointsSlippage`: reconstructed exactly from the fill prices |
84
+ | What did each instrument earn? | positions and fills per day | position snapshots, fills with prices and quantities |
85
+ | How much capital could the strategy take? | daily volume per traded name | the bundle, folded into sessions |
86
+ | How is the cost model set, in words? | the settings themselves | `PerShare` / `PerDollar`, minimum per order, slippage bps, volume limit |
87
+
88
+ The result reads like an execution and risk desk's review of the backtest,
89
+ not a restatement of its equity curve.
90
+
91
+ ## What is in a report
92
+
93
+ Charts on the left and narrow tables on the right in a 960px column, in the
94
+ QuantStats Pro look (white ground, light grid, the same palette: strategy
95
+ `#6B9E00`, benchmark `#5C5C5C`), so the two reports read as one product.
96
+ Every chart is SVG; the page has no external requests. The header and footer
97
+ name the Zipfolio version that built the page and link back to this repository.
98
+ The default title is "Zipfolio Tearsheet: Portfolio, Execution & Cost Analysis"
99
+ (`title=` changes it).
100
+
101
+ | Section | Shown when | Contents |
102
+ | --- | --- | --- |
103
+ | **Performance** | always | key metrics, cumulative returns, underwater curve -- deliberately short; returns are QuantStats' job |
104
+ | **Positions** | the strategy traded | exposure, top positions, long/short concentration, holdings, gross leverage |
105
+ | **Instruments** | traded | each name's PnL, contribution, weight, days held, trade stats; contribution by year; daily and round-trip return distributions per name; cumulative PnL by name |
106
+ | **Sector Analysis** | a held name has a sector | allocation over time, average and peak, profit attribution by GICS sector |
107
+ | **Factor Analysis** | a factor model is set | Fama-French 5 + momentum betas with Newey-West t-stats, alpha, fit, attribution (overall and by year), rolling betas, return decomposition |
108
+ | **Portfolio Risk** | always (more when traded) | VaR/CVaR/EVaR, drawdown-at-risk/CDaR/EDaR, Ulcer index, Gini mean difference; rolling tail risk; risk contribution per holding; clustered correlations; the same names under four allocation rules, walk-forward |
109
+ | **Transactions** | traded | trading frequency, fill sizes, buys and sells, turnover, volume, fill times on the market's own clock |
110
+ | **Execution** | orders are given | how the backtest fills orders, realism checks, orders by type, fill statistics, fill price within the bar and against its typical price, share of bar volume, implementation shortfall, waits |
111
+ | **Trading Costs** | traded | the cost model in plain words, cost summary and per symbol, costs over time, returns before and after costs, sensitivity to extra slippage |
112
+ | **Round Trips** | 5+ round trips | summary, PnL, duration and return statistics, per symbol, lifetimes, distributions |
113
+ | **Capacity** | daily bars are given | days to liquidate, fills over 5% of daily volume, Sharpe across capital bases |
114
+
115
+ A section that cannot be computed becomes a short note, a chart that fails is
116
+ left out, and both are logged; the page fails only if nothing at all can be
117
+ reported.
118
+
119
+ ## Zipfolio and pyfolio
120
+
121
+ Zipfolio stands on [pyfolio-reloaded](https://github.com/stefan-jansen/pyfolio-reloaded)
122
+ and owes it most of its analytics. What it takes, what it changes, and what it
123
+ adds:
124
+
125
+ **Uses pyfolio for the computation.** Performance statistics, drawdown tables,
126
+ exposures and concentration, top positions, turnover, round-trip extraction and
127
+ statistics, profit attribution, sector exposure, liquidity and the capacity
128
+ sweep, slippage sensitivity -- all are pyfolio's functions (`timeseries`,
129
+ `pos`, `txn`, `round_trips`, `capacity`, `plotting.plot_*`).
130
+
131
+ **Replaces the presentation.** pyfolio is written for a notebook: tables go to
132
+ IPython's `display`, and each tear sheet is one tall seaborn figure of a dozen
133
+ panels. Zipfolio does not call the `create_*_tear_sheet` functions. It calls the
134
+ individual `plotting.plot_*` functions, one chart per figure on an axis it
135
+ owns, restyles each (palette, grid, percent axes, legends) and renders it to
136
+ SVG; it catches every table at `utils.print_table` as a *frame* and renders it
137
+ itself, with formatting pyfolio applies one-size-fits-all repaired (counts as
138
+ `146`, money as `-$5,067.13`, three-decimal percentages as two).
139
+
140
+ **Fixes, locally.** pyfolio-reloaded 0.9.9 is used as released; where it
141
+ misbehaves, Zipfolio works around it for the one call that needs it, never by
142
+ patching pyfolio globally:
143
+
144
+ - the capacity analysis fails whenever two names trade on the same day
145
+ (`daily_txns_with_bar_data` calls `asfreq` on duplicate dates) -- a repaired
146
+ copy is swapped in for that call;
147
+ - the transaction-time chart is fixed to New York's 09:30-16:00 -- Zipfolio
148
+ draws its own, on the market's clock and over the hours fills actually fall in;
149
+ - the exposure panel disappears when pandas draws a regular-frequency index in
150
+ period ordinals -- charts are drawn with matplotlib dates;
151
+ - labels and heatmap numbers that collide on dense axes are thinned and fitted
152
+ after drawing.
153
+
154
+ **Leaves out what QuantStats already shows.** Rolling statistics, return
155
+ distributions, the monthly heatmap and stress events are pyfolio's too, but a
156
+ ZipLime backtest already has them in its QuantStats tearsheet.
157
+
158
+ **Adds what pyfolio does not have.** The Instruments, Execution, Trading Costs
159
+ and Factor Analysis sections, the Portfolio Risk section (computed with
160
+ [skfolio](https://github.com/skfolio/skfolio)), sector analysis from a GICS
161
+ table you supply, and the cost model described in words.
162
+
163
+ ## Zipfolio and ziplime
164
+
165
+ Zipfolio is the reporting layer of ZipLime: it is designed around what a
166
+ ziplime 1.20 run produces, and the `zipfolio.ziplime` module reads the parts a
167
+ return series loses.
168
+
169
+ What it relies on from ziplime:
170
+
171
+ - **Orders as objects** -- `execution_style` (market, limit, stop, stop-limit),
172
+ `created` and `dt`, `amount` and `filled`, `limit` and `stop`, `status` and
173
+ `reason`, and `commission`, which ziplime charges to the order rather than the
174
+ fill.
175
+ - **Fills with their order** -- each transaction carries its `order_id`,
176
+ `amount`, `price` and simulation time.
177
+ - **The market-data bundle** -- a polars frame of OHLCV bars per instrument,
178
+ daily or intraday, that the simulation read; `zipfolio.ziplime.execution_bars`
179
+ joins every fill and every order to it *as of* the simulation time, and
180
+ `daily_bars` folds it into sessions.
181
+ - **The cost and execution models** -- `PerShare` / `PerDollar` commission with
182
+ a per-order minimum, `FixedBasisPointsSlippage` with a volume limit,
183
+ `same_bar_execution` and `price_used_in_order_execution`. Zipfolio describes
184
+ them in words and checks every fill against them.
185
+ - **Positions and cash per bar** -- position snapshots taken during
186
+ `run_simulation_iter` (ziplime mutates position objects later, so they are
187
+ copied as they are emitted) and `ending_cash` from the performance frame.
188
+
189
+ ```python
190
+ from zipfolio.ziplime import daily_bars, execution_bars, order_type
191
+
192
+ # while the run's bundle is still loaded:
193
+ bars = daily_bars(bundle) # symbol, day, price, volume
194
+ found = execution_bars(bundle, fills, orders) # fills: id, symbol, dt; orders: id, symbol, created
195
+ fill_bars, decisions = found["fill_bars"], found["decision_prices"]
196
+ kind = order_type(order) # "market", "limit", "stop", "stop_limit"
197
+ ```
198
+
199
+ The ZipLime backtester calls exactly this after every simulation and passes the
200
+ frames to `build_tearsheet`. Nothing in the report requires ziplime itself:
201
+ the inputs are plain pandas frames, and any backtester that can produce them
202
+ gets the same report.
203
+
204
+ ## Installation
205
+
206
+ ```bash
207
+ pip install zipfolio
208
+ ```
209
+
210
+ With the optional parts:
211
+
212
+ ```bash
213
+ pip install "zipfolio[all]" # everything
214
+ pip install "zipfolio[risk]" # + skfolio, for the Portfolio Risk section
215
+ pip install "zipfolio[ziplime]" # + polars, for zipfolio.ziplime
216
+ ```
217
+
218
+ Without skfolio the Portfolio Risk section is left out; nothing else changes.
219
+ Requires Python 3.10+.
220
+
221
+ Until the first release reaches PyPI, or for the latest unreleased code,
222
+ install from GitHub:
223
+
224
+ ```bash
225
+ pip install "zipfolio[all] @ git+https://github.com/Limex-com/zipfolio"
226
+ ```
227
+
228
+ ## Releases
229
+
230
+ Zipfolio is published on GitHub first and then on PyPI, under the same
231
+ version: a version is tagged here (`v0.1.0`), and the wheel built from that tag
232
+ is uploaded to PyPI as `zipfolio`. Every report says which version built it --
233
+ in the header ("Generated by ZipLime Zipfolio v0.1.0") and the footer, both
234
+ linking back to this repository -- so a report can always be traced to the code
235
+ that made it. Changes are listed in [CHANGELOG.md](CHANGELOG.md).
236
+
237
+ To publish a release:
238
+
239
+ ```bash
240
+ poetry version 0.1.1 # or: patch / minor / major
241
+ git commit -am "Zipfolio 0.1.1" && git tag v0.1.1 && git push --tags
242
+ poetry build && poetry publish # PyPI token configured with `poetry config pypi-token.pypi ...`
243
+ ```
244
+
245
+ ## Inputs
246
+
247
+ All frames are plain pandas. Only `returns` is required; each input switches
248
+ on the sections that need it.
249
+
250
+ | Argument | Shape | Used by |
251
+ | --- | --- | --- |
252
+ | `returns` | per-period strategy returns, datetime index | everything |
253
+ | `benchmark` | benchmark returns, same index, or `None` | Performance, Portfolio Risk |
254
+ | `position_records` | rows of `date, symbol, quantity, last_sale_price` per open position per day | Positions, Instruments, Sectors, Risk, Round Trips |
255
+ | `cash` | cash at the end of each period | (same) |
256
+ | `transactions` | rows of `id, order_id, dt, symbol, quantity, price` | Instruments, Transactions, Execution, Costs, Round Trips |
257
+ | `orders` | rows of `id, created, dt, type, symbol, quantity, filled, commission, limit, stop, status, reason` | Execution, Trading Costs, Instruments |
258
+ | `fill_bars` | `open, high, low, close, volume` indexed by fill `id` | Execution |
259
+ | `decision_prices` | `decision_price` indexed by order `id` | Execution (shortfall) |
260
+ | `market_data` | rows of `symbol, day, price, volume` | Capacity, Portfolio Risk |
261
+ | `cost_settings` | `commission_model, commission_per_share, commission_rate, commission_min_trade_cost, slippage_basis_points, slippage_volume_limit, price_used_in_order_execution, same_bar_execution, capital` | Trading Costs, Execution |
262
+ | `sector_mappings` | `{symbol: sector}`; `us_sector_mappings(["AAPL@XNGS", ...], table=...)` gives GICS sectors for US listings from your table | Sector Analysis |
263
+ | `factor_model` | `"ff5_mom"` (default), `"ff5"`, `"ff3"`, `"ff3_mom"` or `None` | Factor Analysis |
264
+ | `factor_data` | your own factor returns (decimals, with `RF`), instead of the download | Factor Analysis |
265
+ | `title` | the page title; defaults to `zipfolio.DEFAULT_TITLE` | header |
266
+ | `market_timezone` | e.g. `"Europe/Moscow"`; defaults to `ZIPFOLIO_MARKET_TIMEZONE`, then New York | fill-time chart |
267
+
268
+ `build_tearsheet` returns the titles of the sections that made it into the page.
269
+
270
+ ## Data the package fetches or ships
271
+
272
+ - **Fama-French factors** are downloaded from Kenneth French's
273
+ [data library](https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html)
274
+ -- the same files `pandas_datareader.famafrench` reads, without the
275
+ dependency -- and cached for a week under `~/.cache/zipfolio`
276
+ (`ZIPFOLIO_CACHE_DIR`). A failed download falls back to a stale cache, then to
277
+ a note in the report; the timeout is 8 seconds. The library publishes monthly
278
+ with a lag, so the last weeks of a fresh backtest may fall outside it. The
279
+ factors describe US stocks: pass `factor_model=None` for other markets.
280
+ - **GICS sectors are not shipped.** The classification is licensed by MSCI
281
+ and S&P, so the codes are yours to bring: a CSV of `symbol,gics_sector`
282
+ (two-digit sector code) passed as `us_sector_mappings(listings, table=...)`
283
+ or found through `ZIPFOLIO_GICS_TABLE`. `scripts/build_us_sector_map.py`
284
+ builds one from exports that carry GICS codes, one row per ticker from its
285
+ most recent classification. `us_sector_mappings` looks up only listings on
286
+ US venues, so a Moscow `T` is not filed as AT&T; a reused ticker gets its
287
+ current holder's sector. Or skip the table and pass `sector_mappings`
288
+ yourself -- any `{symbol: sector}` works, GICS or not.
289
+
290
+ ## Limitations
291
+
292
+ - Futures exposure is understated: position values are quantity x price, and
293
+ the records carry no contract multiplier.
294
+ - Slippage is reconstructed for the fixed-basis-point model; other slippage
295
+ models would need their own reconstruction.
296
+ - Instrument contribution adds daily PnL over the start-of-day portfolio value,
297
+ so dollars and percent can disagree in sign for a name that earned early and
298
+ gave back later -- the report says so where it shows them.
299
+ - Factor analysis needs at least 60 sessions inside the factor data.
300
+
301
+ ## Development
302
+
303
+ ```bash
304
+ pip install -e ".[all]" pytest # or: poetry install --all-extras
305
+ pytest
306
+ ```
307
+
308
+ Tests never touch the network: factor downloads are replaced by synthetic
309
+ factors. Release notes are in [CHANGELOG.md](CHANGELOG.md).
310
+
311
+ ## License
312
+
313
+ Apache License 2.0 -- see [LICENSE](LICENSE). Zipfolio builds on
314
+ pyfolio-reloaded (Apache-2.0) and skfolio (BSD-3-Clause). No market or
315
+ classification data is distributed with it.
316
+