topstep-backtest 0.1.0__py3-none-any.whl

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 (44) hide show
  1. topstep_backtest/__init__.py +43 -0
  2. topstep_backtest/clock/__init__.py +1 -0
  3. topstep_backtest/clock/live_clock.py +82 -0
  4. topstep_backtest/clock/test_clock.py +133 -0
  5. topstep_backtest/core/__init__.py +1 -0
  6. topstep_backtest/core/ids.py +23 -0
  7. topstep_backtest/core/instruments.py +167 -0
  8. topstep_backtest/core/money.py +160 -0
  9. topstep_backtest/core/time.py +125 -0
  10. topstep_backtest/data/__init__.py +1 -0
  11. topstep_backtest/data/clean.py +86 -0
  12. topstep_backtest/data/feed.py +56 -0
  13. topstep_backtest/data/synthetic.py +137 -0
  14. topstep_backtest/data/validator.py +215 -0
  15. topstep_backtest/data/wrangler.py +306 -0
  16. topstep_backtest/engine/__init__.py +1 -0
  17. topstep_backtest/engine/backtest.py +209 -0
  18. topstep_backtest/execution/__init__.py +1 -0
  19. topstep_backtest/execution/rejections.py +53 -0
  20. topstep_backtest/execution/sim_broker.py +1436 -0
  21. topstep_backtest/fills/__init__.py +1 -0
  22. topstep_backtest/fills/bar_fill.py +268 -0
  23. topstep_backtest/fills/fees.py +120 -0
  24. topstep_backtest/fills/path.py +59 -0
  25. topstep_backtest/harness.py +446 -0
  26. topstep_backtest/indicators/__init__.py +46 -0
  27. topstep_backtest/indicators/base.py +57 -0
  28. topstep_backtest/indicators/library.py +303 -0
  29. topstep_backtest/indicators/talib_adapter.py +657 -0
  30. topstep_backtest/metrics/__init__.py +5 -0
  31. topstep_backtest/metrics/stats.py +153 -0
  32. topstep_backtest/protocols.py +473 -0
  33. topstep_backtest/py.typed +0 -0
  34. topstep_backtest/rules/__init__.py +1 -0
  35. topstep_backtest/rules/kernel.py +281 -0
  36. topstep_backtest/rules/params.py +74 -0
  37. topstep_backtest/strategy/__init__.py +20 -0
  38. topstep_backtest/strategy/base.py +118 -0
  39. topstep_backtest/strategy/symbol.py +344 -0
  40. topstep_backtest/strategy/tracker.py +151 -0
  41. topstep_backtest-0.1.0.dist-info/METADATA +250 -0
  42. topstep_backtest-0.1.0.dist-info/RECORD +44 -0
  43. topstep_backtest-0.1.0.dist-info/WHEEL +4 -0
  44. topstep_backtest-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,250 @@
1
+ Metadata-Version: 2.4
2
+ Name: topstep-backtest
3
+ Version: 0.1.0
4
+ Summary: Event-driven backtesting framework for Topstep Trading Combine strategies, with backtest/live parity against topstep-sdk.
5
+ Author-email: Tarric Sookdeo <tarricsookdeo@outlook.com>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Keywords: backtesting,combine,futures,prop-firm,topstep,trading
9
+ Classifier: Development Status :: 2 - Pre-Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Intended Audience :: Financial and Insurance Industry
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Topic :: Office/Business :: Financial :: Investment
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.12
20
+ Requires-Dist: msgspec<1.0,>=0.18
21
+ Requires-Dist: ta-lib<0.8,>=0.7.1
22
+ Requires-Dist: topstep-sdk<0.2,>=0.1.2
23
+ Requires-Dist: tzdata>=2024.1; sys_platform == 'win32'
24
+ Provides-Extra: data
25
+ Requires-Dist: pandas>=2.2; extra == 'data'
26
+ Provides-Extra: dev
27
+ Requires-Dist: hypothesis>=6.100; extra == 'dev'
28
+ Requires-Dist: pandas>=2.2; extra == 'dev'
29
+ Requires-Dist: pyright>=1.1.380; extra == 'dev'
30
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
31
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
32
+ Requires-Dist: pytest>=8.0; extra == 'dev'
33
+ Requires-Dist: ruff<0.17,>=0.16; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # topstep-backtest
37
+
38
+ An event-driven backtesting framework for developing futures strategies that can
39
+ **profitably pass the Topstep Trading Combine**.
40
+
41
+ Its defining property is **backtest/live parity** with the companion
42
+ `topstep-sdk`: a strategy is written **once** against structural protocols that
43
+ both the deterministic `SimBroker` *and* the live `AsyncTopstepClient` satisfy.
44
+ Its core differentiator is a first-class **prop-firm rule engine**: the two-state
45
+ trailing Maximum Loss Limit, optional Daily Loss Limit, consistency target,
46
+ position caps, and session flatten are enforced *in real time* (including
47
+ intrabar forced liquidation with adverse slippage), not scored after the fact.
48
+
49
+ ```python
50
+ class SmaCross(SymbolStrategy):
51
+ def __init__(self, contract_id: str) -> None:
52
+ super().__init__(contract_id)
53
+ self.fast = self.use(Sma(20)) # TA-Lib, driven bar by bar, causal by construction
54
+ self.slow = self.use(Sma(50))
55
+ self.cross = self.use(Cross(self.fast, self.slow))
56
+
57
+ async def on_bar(self, bar: Bar) -> None: # gated until every use()d indicator is ready
58
+ if self.cross.up and self.position.flat:
59
+ await self.buy( # sugar over ctx.orders — the topstep-sdk surface
60
+ 2,
61
+ stop_loss_ticks=40,
62
+ take_profit_ticks=80, # signed-tick OCO bracket
63
+ )
64
+ ```
65
+
66
+ ## Install
67
+
68
+ ```bash
69
+ pip install topstep-backtest
70
+ pip install "topstep-backtest[data]" # adds pandas, for DataFrame input
71
+ ```
72
+
73
+ Requires Python 3.12+. TA-Lib is a core dependency and ships wheels for common
74
+ platforms; on others you will need the TA-Lib C library first.
75
+
76
+ ```python
77
+ from datetime import date
78
+ from decimal import Decimal
79
+
80
+ from topstep_backtest import AccountSize, Backtest, SymbolStrategy
81
+ from topstep_backtest.core.instruments import spec_for_symbol
82
+ from topstep_backtest.data.synthetic import synthetic_bars
83
+ from topstep_backtest.indicators import Cross, Sma
84
+
85
+ MNQ = "CON.F.US.MNQ.U26"
86
+
87
+
88
+ class SmaCross(SymbolStrategy):
89
+ def __init__(self, contract_id: str) -> None:
90
+ super().__init__(contract_id)
91
+ self.fast = self.use(Sma(10))
92
+ self.slow = self.use(Sma(30))
93
+ self.cross = self.use(Cross(self.fast, self.slow))
94
+
95
+ async def on_bar(self, bar) -> None:
96
+ if self.cross.up and self.position.flat:
97
+ await self.buy(1, stop_loss_ticks=40, take_profit_ticks=80)
98
+ elif self.cross.down and self.position.is_long:
99
+ await self.close()
100
+
101
+
102
+ bars = synthetic_bars(
103
+ contract_id=MNQ,
104
+ spec=spec_for_symbol("MNQ"),
105
+ start_day=date(2026, 5, 4),
106
+ days=5,
107
+ seed=7,
108
+ start_price=Decimal("23000.00"),
109
+ bars_per_day=120,
110
+ vol_ticks=12,
111
+ )
112
+ print(Backtest(bars, SmaCross(MNQ), account=AccountSize.S50K).run())
113
+ ```
114
+
115
+ Feeding your own data (e.g. normalized Databento candles):
116
+
117
+ ```python
118
+ from topstep_backtest.data.wrangler import bars_from_dataframe
119
+
120
+ bars = bars_from_dataframe(
121
+ df,
122
+ contract_id="CON.F.US.MNQ.U26",
123
+ spec=spec,
124
+ unit=AggregateBarUnit.MINUTE,
125
+ unit_number=1,
126
+ stamp="open",
127
+ ) # declare what your timestamps mean!
128
+ ```
129
+
130
+ `bars_from_records` is the same loader without the pandas dependency.
131
+
132
+ ## Status and limitations
133
+
134
+ **Pre-alpha (0.1.0).** The engine core is well covered — exact-Decimal money on
135
+ the tick grid, FIFO lot accounting, a structurally enforced no-look-ahead
136
+ firewall, and byte-identical reruns — but read these before trusting a number:
137
+
138
+ - **The rule and fee constants are NOT calibrated against a live account.** They
139
+ are researched, source-cited config (docs/topstep-rules.md §9 has 8 unchecked
140
+ boxes). Treat a `PASSED`/`FAILED` verdict as a diagnostic, not an answer, and
141
+ distrust any result landing within a tick or a fee of a limit.
142
+ - **No exchange holiday calendar ships with this package.** Bars on market
143
+ holidays and past early-close halts are not detected, flagged or filtered
144
+ anywhere — filter them upstream. (A built-in calendar was removed in 0.1.0: it
145
+ disagreed with CME on several dates a year and silently discarded tradable
146
+ sessions, which is worse than not having one.)
147
+ - **One contract per run, inside a single front-month window.** There is no
148
+ continuous-contract stitching, and no roll detector. A multi-month export
149
+ spanning a quarterly roll is silently merged into one price series.
150
+ - **Tier-0 bar fills only.** Market orders fill at the next bar's open and
151
+ default to zero slippage, so a strategy whose edge is thinner than roughly
152
+ 8–10 ticks per round turn is inside the model's error bars. Event windows
153
+ (08:30 ET releases and the like) are not honestly modelled at bar resolution.
154
+ - **Untested end to end:** multi-symbol runs, `dll_enabled=True`, and
155
+ non-quarter-tick products (CL, GC).
156
+
157
+ What is proven is *structural* parity — pyright-strict conformance plus a
158
+ signature-diff test against the live SDK. The behavioural gate (an intent-sequence
159
+ test against a recording live broker) is **not built yet**; see docs/ROADMAP.md.
160
+
161
+ ## What works today
162
+
163
+ - **Rule kernel** (`rules/`) — the canonical Topstep Combine rulebook: EOD-ratcheting
164
+ trailing MLL with permanent lock at the starting balance, real-time breach on
165
+ realized+unrealized equity, optional DLL (flatten-and-lock, not a fail),
166
+ consistency (`best_day ≤ 50% × total`), fixed 5/10/15-mini position caps —
167
+ golden-fixtured against the documented worked examples.
168
+ - **Deterministic engine** (`engine/`, `clock/`) — single time-ordered loop,
169
+ `TestClock`, strict `ts_init` ordering assertions, bit-for-bit reproducible runs.
170
+ - **SimBroker** (`execution/`) — full order lifecycle (market/limit/stop/trailing,
171
+ signed-tick OCO brackets), netting + exact-Decimal P&L, gateway-parity `APIError`
172
+ rejections tallied on the result, intrabar fill-vs-breach resolution along one
173
+ pessimistic price path, forced liquidation whose loss can exceed the floor.
174
+ - **Tier-0 fills** (`fills/`) — pessimistic bar fills: adverse-extreme-first path,
175
+ next-bar-open for close signals, gap-through at the open, ≥1-tick stop slippage,
176
+ trade-through (not touch) limit fills; per-side/per-instrument Topstep fee stack,
177
+ correctable via `Backtest(..., fee_model=TopstepFees(overrides={...}))`.
178
+ - **Data layer** (`data/`) — pandas/records → validated `Bar` streams (explicit
179
+ open/close stamping kills the off-by-one-bar look-ahead), tick-grid validation,
180
+ session/halt/weekend checks, deterministic synthetic generator.
181
+ - **Indicators** (`indicators/`) — every indicator is TA-Lib: `TalibIndicator` drives 152 of
182
+ its 161 functions bar-by-bar (typed `Sma`/`Ema`/`Rsi`/`Atr`/`Macd`/`BBands`/… wrappers,
183
+ plus a pure-Python `Cross`), so no formula is re-implemented here to drift; the nine
184
+ refused are the ones that could only fail silently. Streaming values are bit-identical to a
185
+ batch run, and the bounded history window is a *parity* decision — preload `history_bars`
186
+ bars live and the live number equals the sim number. Parity begins at `warm` (the window is
187
+ full), not at `ready` (a value exists).
188
+ - **Parity seam** (`protocols.py`) — pyright-strict conformance tests prove
189
+ `AsyncTopstepClient` and `SimBroker` satisfy the same `Broker` protocol, plus a
190
+ signature-diff test against the live SDK that fails the suite on drift.
191
+
192
+ ## Development
193
+
194
+ From a checkout (the sibling `topstep-sdk` repo is expected at `../topstep-sdk`;
195
+ set `UV_NO_SOURCES=1` to resolve it from PyPI instead):
196
+
197
+ ```bash
198
+ uv sync --extra dev
199
+ uv run pytest && uv run ruff check . && uv run ruff format --check . && uv run pyright
200
+ cd examples && uv run python run_combine.py # end-to-end combine verdict
201
+ ```
202
+
203
+ ## Documentation
204
+
205
+ The source repository is private, so there is no public issue tracker or docs
206
+ site. Everything below ships **inside the sdist** — `pip download --no-binary
207
+ :all: topstep-backtest` and unpack it, or read the copies in your environment.
208
+
209
+ - **`docs/GUIDE.md` — start here**: the user guide (data in, writing strategies,
210
+ wiring runs, reading results, verification checklist).
211
+ - `docs/TUTORIAL_EMA_CROSSOVER.md` — an in-depth walkthrough building one
212
+ strategy end to end.
213
+ - `docs/STRATEGY_API.md` — the strategy dialect reference, including the
214
+ indicator surface.
215
+ - `docs/topstep-rules.md` — the rulebook being enforced, with sources,
216
+ confidence levels, and a verify-before-trusting checklist.
217
+ - `docs/DESIGN.md` — architecture contract (parity seam, no-look-ahead
218
+ invariants, fill tiers). Its §4 layout is the *target* architecture, not the
219
+ current tree.
220
+ - `AGENTS.md` — dense maintainer/agent reference and the real module map.
221
+ - `examples/` — runnable: `run_real_data.py` (your CSV/Parquet → verdict),
222
+ `run_combine.py` (synthetic end-to-end), `ema_cross.py`, `sma_cross.py`,
223
+ `talib_macd.py`.
224
+
225
+ ## Roadmap
226
+
227
+ Analytics + Monte-Carlo pass-probability → live adapter + calibration → L1/L2/MBO
228
+ fill tiers. Funded-account (XFA) modeling is deliberately parked. See
229
+ `docs/ROADMAP.md` in the sdist.
230
+
231
+ ## Stack
232
+
233
+ Python 3.12+ · `topstep-sdk` · `msgspec` · `TA-Lib` · `uv` · `ruff` · `pyright`
234
+ (strict) · `pytest` + `hypothesis`. Canonical timezone: **ET** (`America/New_York`);
235
+ internal hot path is int-ns UTC; all money is exact `Decimal` on the tick grid —
236
+ indicator values cross from float64 into `Decimal` and are deliberately *not*
237
+ tick-snapped (an indicator level is not a tradeable price).
238
+
239
+ ## License
240
+
241
+ MIT — see LICENSE.
242
+
243
+ > **Unofficial.** Not affiliated with, endorsed by, or sponsored by Topstep, LLC
244
+ > or ProjectX Trading, LLC. "Topstep" is a trademark of its respective owner and
245
+ > is used here only to identify the evaluation program this tool models. Rule
246
+ > numbers researched July 2026 — re-verify against Topstep's help center before
247
+ > trusting a pass verdict (see the checklist in docs/topstep-rules.md §9).
248
+ >
249
+ > **Not financial advice.** This software simulates a trading evaluation and can
250
+ > be wrong. You are solely responsible for any capital you risk.
@@ -0,0 +1,44 @@
1
+ topstep_backtest/__init__.py,sha256=HIPZrU1l55a8MnwbbYV2cCv8W0rsBC8phNT4JXxC70o,1345
2
+ topstep_backtest/harness.py,sha256=5EHYlPfZPI3elRAhlQowByJ20QSh9vrGdU9rPAH_PSU,18536
3
+ topstep_backtest/protocols.py,sha256=JW3Rcc5FkmYlpDvdT2ggZlqTwK1LHzXSnRiomRxteuE,14496
4
+ topstep_backtest/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ topstep_backtest/clock/__init__.py,sha256=-1bP9fiBx8mK5h7H2vvwaTrG7IUFSltphfbbq6bCASw,29
6
+ topstep_backtest/clock/live_clock.py,sha256=Xu6bSftmpLU4s1vXTYJAUNk5wYJpLLXkhJM0wmLtdfs,2991
7
+ topstep_backtest/clock/test_clock.py,sha256=t3mNe6mmkVvfPts-4x6pTu8ryQRL-_ykHBMUuT_9tx0,5232
8
+ topstep_backtest/core/__init__.py,sha256=wZnQvx-BeE-p1W2iM-EdEesEL6uhDxJbL8OQfjxHNYY,28
9
+ topstep_backtest/core/ids.py,sha256=x7OhTdHET3u7QBoQCNqq5dDuV9DECSdWewg5WjIjMaY,589
10
+ topstep_backtest/core/instruments.py,sha256=IC90ZAjYSHJoDbIfTMObkStMsgyugFzZTwH675qeb-0,5913
11
+ topstep_backtest/core/money.py,sha256=magYcXDi-6tfN1OuHa28e3Mq8hSlnN3cJj7Sh6CA6SY,5146
12
+ topstep_backtest/core/time.py,sha256=qFUBfx3ERQopYqpMN7e1l9nVfOnj7CVamXa0FMwy5YM,4285
13
+ topstep_backtest/data/__init__.py,sha256=VV89qwuA8bQjHYOKb9IZuZmKaxFjNBjs6N4OwP9cR60,28
14
+ topstep_backtest/data/clean.py,sha256=RRhUAasPOC9-QIH2Djubtiws76wWuqEe3WIr980OTDg,3509
15
+ topstep_backtest/data/feed.py,sha256=rV_qRmJlQc-12fTPaYAlYpcr9rBYW38CZagTUA0DSy0,2231
16
+ topstep_backtest/data/synthetic.py,sha256=V1UiWe_bndefwRYqvxX8lf3WJVuqhHtrZ5zRnPPynTA,5327
17
+ topstep_backtest/data/validator.py,sha256=GCLf7ziAe8c5E5sJIec-4fnJsTR5V7XJMMmTt_zO3Dc,8568
18
+ topstep_backtest/data/wrangler.py,sha256=0cI23QMvOjN28YavQz4oXtgg5VkFVd8n6Pjxh2zgwtI,12222
19
+ topstep_backtest/engine/__init__.py,sha256=N1G8vIKcwGZ-dL5XfFu83Q2K_vnZ0FyWh96dEx0Agx4,30
20
+ topstep_backtest/engine/backtest.py,sha256=sH9oJZxuVKPjqWQQzqrDMvEF_RLtwBmvTRmGbnJADGM,8041
21
+ topstep_backtest/execution/__init__.py,sha256=1QbZfFdYSjDz8JMbsARLYdwNHRjB0a4Su66zcaILf3g,33
22
+ topstep_backtest/execution/rejections.py,sha256=8N05iizTHpaoub-2Bv5Oupoi8gmHYyObnXzr4ryPl-I,1647
23
+ topstep_backtest/execution/sim_broker.py,sha256=hfF_Bg7srZ3oTsC52xNNWCCIOxNL8sRIQ93CU2i3qbc,57317
24
+ topstep_backtest/fills/__init__.py,sha256=zN0kFAwMUM8RfQ4US3CxnxEc4sXpBRCmIEnyePeoWMY,29
25
+ topstep_backtest/fills/bar_fill.py,sha256=s4fN1P9Q_mdFXcTf-l0mSdHtAX0MnADpXrp3MCOTsRU,11720
26
+ topstep_backtest/fills/fees.py,sha256=t6mey1ivybe2wb61yC_QGm-skimp73EMLkwvxn3dEn4,4363
27
+ topstep_backtest/fills/path.py,sha256=fCpFO2i7J5ELYj_nB7frAw6f91GnjaA6_dRRwIsWCkY,2307
28
+ topstep_backtest/indicators/__init__.py,sha256=pyQCJ1IzxLXNlClqC3fEpIko_UZ-v_LDIsrEp5RnWEQ,890
29
+ topstep_backtest/indicators/base.py,sha256=NBrX9A6VoEHBq3HFhnNGEjdd-_5tjTmNRBHil_wHX4I,1539
30
+ topstep_backtest/indicators/library.py,sha256=TXK4s5h5aDrdNIpbLYIYOXiBPJ_jMoaicROqWYm707A,10484
31
+ topstep_backtest/indicators/talib_adapter.py,sha256=4QxjyIYEHJl8rq_ClCyAigF1NXJHPwo_1D8sYPG2mL4,27125
32
+ topstep_backtest/metrics/__init__.py,sha256=-P-K6NRm7PRxuvy-TmZQ6fWFZt5Z3D0lodypeZmqHpk,128
33
+ topstep_backtest/metrics/stats.py,sha256=LcZ1o6BnH0yqNcCpy02726T77uT_mPnPM5P_jzBMxtg,6658
34
+ topstep_backtest/rules/__init__.py,sha256=D3-Hn-6biaZu84I-gvbb5WcE1kKvKodPFn6_bA8_BGY,29
35
+ topstep_backtest/rules/kernel.py,sha256=E2rwoxJTzUVhTxWKhDnzmAUovS_rJmyEXjyRM4Pmz6s,10394
36
+ topstep_backtest/rules/params.py,sha256=-ljFgFDCWcUk_u6hvzosdYPXZpsUVlFWerbbAgbYIKk,2616
37
+ topstep_backtest/strategy/__init__.py,sha256=iCvVXBha4Vudti9JEmeDdGsfPiSTxQeVEH6mDX8KzDM,391
38
+ topstep_backtest/strategy/base.py,sha256=pvZvDFo38heroy0GO4hIMIKqTh1Ch35a-yJbv5xH0hU,3996
39
+ topstep_backtest/strategy/symbol.py,sha256=Fnrid3S_tpT8wzxuneLIcV6oH58ezUQY9ahZdB5Hrps,13497
40
+ topstep_backtest/strategy/tracker.py,sha256=b04RMU7CBDR7HVcqFUj5pXxyTu_5sJGnbwKiKQ5qsXA,5157
41
+ topstep_backtest-0.1.0.dist-info/METADATA,sha256=yKeBs9fqcrqFjHUEfWeFGEtazUeIVjnrILGvAxfwwy8,11456
42
+ topstep_backtest-0.1.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
43
+ topstep_backtest-0.1.0.dist-info/licenses/LICENSE,sha256=YKxnmeFF9Cf9zJwyjJLZMJ2ve0xCXNBCWCD-Mrw5Ctw,1071
44
+ topstep_backtest-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tarric Sookdeo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.