tradefloor
tradefloor is a market simulator you can run a strategy against. It has a Rust core and a Python API.
Give it a seed and a list of companies. It runs a market forward: prices, a limit order book, fills, and an economy that moves each day. Your orders match against the book's depth, so your trades move the price.
Real market data can't tell you what would have happened if you had traded differently, or what caused a move. tradefloor can, because it computed every price.
Documentation
Documentation is at https://tradefloor.dev. It covers install, core concepts, the realism envelope, presets, the API and the notebooks.
Three documents in this repository are for anyone publishing with it:
- docs/MODEL.md: the model as equations, with every coefficient's value on the default preset and where it came from
- docs/STATISTICS.md: the named sets of realism statistics, so a count on one page can be matched to a count on another
- docs/SUPPORT.md: which release lines get fixes, and for how long
Install
pip install tradefloor
tradefloor was called pretium until 0.5.0. Versions up to 0.4.3 can still be installed under that name, and results recorded with them still replay. The rename changed nothing in the model.
There are wheels for Linux, macOS and Windows on CPython 3.11+, and no
dependencies. The same engine is a Rust crate (cargo add tradefloor).
The API may change before 1.0. Model changes ship as new presets, so a market with no agent orders in it replays exactly on its named preset in later releases. Seed determinism says what holds for a run with agent orders in it.
The demo
The examples are in this repository and not in the package, so clone it first:
git clone https://github.com/simoncoombes/tradefloor
cd tradefloor
python examples/rate-shock/counterfactual.py
Run an agent in a controlled market, checkpoint the world and fork it, then raise rates by 200bps in one branch and compare what the same agent does next. The wheel carries the library and not the examples, so the clone is what puts the script on disk.
The run takes under five seconds of CPU and needs no keys and no network. It prints the nine checks that show the two branches started identical, the step at which the agent's behavior changed, and the two branches side by side. The walkthrough is Your first counterfactual experiment.
First run
import tradefloor as tf
universe = tf.Universe.random(40, seed=111)
spec = tf.StrategySpec.momentum(lookback_days=1.0, top_k=5)
scores = tf.evaluate({"mine": spec}, seed=7, universe=universe, days=10)
scores["mine"].return_pct # what it made
scores["mine"].impact_bps # what its own footprint cost
scores["mine"].strategy_fingerprint # sha256, cite this
scores["mine"].errors # each step that raised or was refused
scores["mine"].sharpe # annualised, from the daily closes
scores["mine"].time_in_market # share of steps holding a position
That result comes from one random market, so it says as much about the seed
as about the strategy. tf.rank runs many seeds and compares strategies with
a paired sign test.
Every evaluate and rank run starts at day 0, so a rule that needs 20
days of prices would sit out the first 20 days while buy-and-hold is
invested, which counts against it in the comparison. history_days=20 runs
the market for 20 days before day 0 with nobody trading, and
obs.history.bars(ticker, last=20) returns those days' bars at the first
decision. Each scored day joins the history after its close, and
obs.history.macro() gives the published macro figures for the same days.
The scored days continue the warmed market, so on the same seed they are
different days from a run without the warm-up, and the scorecard records
history_days. The reference agents and StrategySpec strategies keep
their own price history and do not read obs.history.
Add tf.baselines.reference_agents() to the entrants to read a score against
buy-and-hold on the same market: tf.versus_buy_and_hold(scores) gives each
agent's P&L less buy-and-hold's. The reference set includes an Oracle that
reads the model's fair value. On pt-v19 and earlier tf.capture_ratio(scores)
gives each P&L as a fraction of the Oracle's. On pt-v20, the default, it
returns {} and warns why: market moves there mostly stick, so even perfect
knowledge of fair value leaves little edge, and buy-and-hold is the
comparison to quote.
The agent's view
A Python agent implements act(obs) and returns orders. obs.engine is a
read-only market view: prices, the public columns, each book, the bars of
days already recorded (a World run with record=True; tf.evaluate records
none), the published macro fields, the curve and which names have news today.
obs.history holds a daily bar per name and the published macro for every
day the run has closed, in evaluate, rank, World and tca.analyse,
and needs no extra package. A bar's close is the day's last print. On
pt-v20 the market's close then re-marks every name, so the next day starts
from a different price: 15 bp away at the median on a 20-name roster. A
broker's daily bar closes at the official close.
obs.portfolio reads the agent's own positions and cannot trade. Forking the
engine, writing to it and reading the hidden state all raise
tf.SandboxError. The hidden state includes the true business-cycle phase;
the macro fields carry the phase as published. The gym environment's env.engine and
env.portfolio are the same views.
In the mapping act returns, a plain number is a market order for that many
shares, negative to sell. A native Python agent can also return
tf.Limit(quantity, price), which waits in the book for what does not fill,
and tf.Cancel(). The framework adapters can send all three: an LLM's action
with a limit_price becomes a tf.Limit, and side: "CANCEL" becomes a
tf.Cancel(). There are no stop, stop-limit or bracket orders, so a stop has to be checked at each
step: at six steps a day an emulated stop filled a median 26.5 bp past its
level, 9 bp at 5-minute steps, and 540 bp at the 90th percentile in the
packaged recession. A trade costs the spread and its impact on the book.
There are no commissions and no borrow fee on a short. Uninvested cash earns
nothing by default. A negative cash balance pays the policy rate before each
close in tf.evaluate, tf.rank and World, which is below a broker's
margin rate, so leverage up to the default max_leverage=2.0 costs at least
that. margin_interest=False makes borrowing free, as it was before 0.8.5,
and cash_interest=True pays the policy rate on idle cash.
Agents in one tf.evaluate or tf.rank call run one after another in one
Python process, on the same seed, so the first agent can leave the price path
in a class variable for a later one, and nothing detects it. The read-only
view guards against accidents, and an agent written to cheat can get round
it. One way round it is unflagged: tf.evaluate's own frames hold the
seed and the universe, an agent can read them through sys._getframe,
build a second tf.Engine from them and run it ahead. The copy count does
not see a newly built engine, so the card says tampered=False. To compare
agents you did not write, or two that might share state, run each in its own
process.
In a World with several agents, orders placed at the same step execute in
label order, alphabetical, for the whole run. Two identical buyers of 10% of
a day's volume paid 19.5 to 30.7 bp apart on seeds 1 to 10, the later label
paying more. Rotate the labels across runs when you compare different agents
in one market.
The Oracle reads hidden state by declaring privileged = True, which gives
it obs.hidden and marks its scorecard. Pass trusted_agents=True for
research that needs the live engine, and every scorecard says so. Either way
the harness compares the engine's state hash around each call, and an agent
that changed the market is scored tampered and left out of tf.rank. So
is a sandboxed agent that forked or snapshotted the engine, however it
reached it.
tradefloor/sandbox.py
lists what the view serves and what the check cannot catch. The view and the
check guard against accident. Agent code runs in the harness's own process, so
it can reach the engine by walking the interpreter, and a read made that way
leaves no trace. Run code you do not trust in a separate process, through the
MCP server.
Contents
engine.truth() |
why each price moved: eleven factors that sum to the mispricing's move, to 1e-16 |
engine.prints() |
how each trade price came about: the shock, and the order book depth that absorbed it |
| counterfactual TCA | your trading cost, from the same seed run with your orders and without them |
tf.rank |
many seeds, paired sign tests |
RunManifest |
version, preset, seed, universe, macro, scenario. reproduce() stops on a mismatch |
World / compare |
fork a running experiment, change one variable, and measure where the two came apart |
| MCP server | thirteen read-only tools for a coding agent, scenarios included |
| more | a Gymnasium environment, Arrow output, checkpoints, SEC EDGAR data, a browser build |
Historical data shows that a stock fell. truth() also says why, for example
that 60% of the fall was order flow, and no historical dataset carries that
label.
The eleven factors sum to the change in mispricing, the log gap between the
price and the model's fair value. On pt-v20 a shock that sticks is booked
whole to random_noise and then taken back out by fair_value_shift, so the
two move against each other (a per-tick correlation of about -0.75 on one
seed) and should be read together. engine.explain(ticker, day) breaks down
the move in the printed price instead. An agent scored on explaining moves
gets an explanation_accuracy: the share of days on which it named the
factor that moved prices most, open to close, summed over every name.
fair_value_shift moves no price and is never that answer. On pt-v20 a
constant answer scores near the top, because random_noise wins almost
every day: answering it every day scores 0.95 to 1.0. So the scorecard
carries explanation_baseline, what a constant answer scores on the same
days, and explanation_edge, the accuracy minus the baseline, and its repr
prints the three together. Only the edge means anything. Quote it, or all
three, and never the accuracy alone.
To drive it from an agent:
pip install "tradefloor[mcp]"
claude mcp add tradefloor -- tradefloor-mcp
Strategies, universes and scenarios are data, so a tool argument cannot reach code. Each result carries its own caveats. See the MCP page.
Controlled scenarios
scenario = tf.Scenario.load("liquidity_crisis") # ships with the package
control, stress = tf.branch(engine, 2)
for day in range(80):
scenario.apply(stress, day)
... # run both branches
A scenario is a file of changes to the market and the assumptions behind them, for controlled experiments. Each change targets a field the engine reads. The file keeps the shock apart from the knock-on effects you assume follow it:
tradefloor scenario show oil_price_spike
Exogenous shocks
----------------------------------------------------------
day 50+ commodity.oil x1.4
Assumed transmission
----------------------------------------------------------
day 55..74 ramp macro.inflation +1.50pp
day 55+ macro.corporate_yield +0.50pp
tradefloor does not predict what a war, an election, an oil shock or a recession will do to markets. You state the assumptions and it measures how an agent behaves under them.
Seven scenarios ship with the package, so Scenario.load works after a plain
pip install. Each one records how big its effect was measured to be. Their
source is here.
tradefloor scenario list names them, and tradefloor scenario targets
lists every target and what each one reaches.
Bonds
Universe.random(40, seed=1, bonds=True) adds three simulated rate indices
after the equities: UST2Y and UST10Y, constant-maturity 2-year and
10-year treasury indices, and IGCORP, an investment-grade corporate bond
index. They are not real securities. Each is priced off the engine's own
curve, returning yield / 252 - D * dy + 0.5 * C * dy**2 a day, with
duration and convexity of 1.9 and 4.6, 8.5 and 84, and 7.0 and 100. They
trade through the same books, fills, portfolio and tape as the equities, and
they leave every equity price unchanged. Scenario.load("curve_shock") moves
the whole curve 200 basis points in one day, which takes about 15% off
UST10Y; tradefloor.baselines.Balanced is a 60/40 portfolio with a drift
band. evaluate(..., cash_interest=True) pays uninvested cash the policy
rate, and is off by default. A negative cash balance is charged the policy
rate in evaluate, rank and World unless you pass
margin_interest=False.
Realism
tradefloor checks its market against real ones with three named sets of statistics. docs/STATISTICS.md lists every member of each, and the counts below refer to them.
The one-year table has 19 statistics of a simulated market, such as
volatility, fat tails, how much stocks move together and how far the VIX
jumps after a fall. tf.facts.measure() reads 18 of them over 252 days, and
tf.facts.crisis_statistics() the nineteenth, which needs a run with a
crisis in it. tf.envelope.score() compares each with the range real
markets show over a year. On the default preset, pt-v20, all 19 are inside
their ranges. The check runs 30 random seeds. Fifteen of the statistics are read on one fixed
set of companies, and that fixed-roster panel is repeated on held-out seeds
and on a held-out set of companies.
The 19 of 19 is a verdict on figures pooled over the 30 seeds, the median
for each shape statistic. One seed's year often misses one or more of the 14
shape statistics: on seeds 101 to 116 all 14 were in range on 5 of the 16,
and one seed had 8 of 14. If you run one market per condition, read
tf.envelope.intervals(), which gives each statistic's spread across seeds
beside its range.
A shape statistic's range is the median of 35 real one-year windows, plus or
minus 2.1 times their trimmed standard deviation. That makes it wide, and
passing it is weak evidence. Volatility clustering shows the gap.
abs_return_acf1 reads 0.028 and abs_return_acf5 0.019, below the lowest
of the ten 2015 to 2025 windows in tf.facts.REAL_MARKETS_WINDOWS (0.039 and
0.034), and both pass because their ranges reach lower than those windows do.
Raising them changes the simulation, so it waits for the next preset.
Four of the 19 describe the index as a whole. An equal-weight index of the stocks gains 7.7 percent a year over one year, inside a real range of 1.1 to 10.3 (pt-v19 gains 7.6). On a day the index falls 1 percent or more, the VIX rises a median 1.7 points, inside a real range of 0.39 to 3.03. On a 3 percent fall it rises 4.3, inside 2.6 to 9.58. The index falls 3 percent or more on 0.89 percent of days, against 1.21 percent in real markets.
The two-year panel is the fixed-roster panel run for 504 days. Fourteen of its 15 statistics have a two-year range, and pt-v20 has all 14 inside.
The long-run criteria are 40 rows over 21 years for pt-v20. The check
runs the market for 21 years, 90 times over, and replays 2008 and 2020 with
the real VIX. The first 15 rows compare what a user would notice with real
markets: how deep crashes go, how long fear lasts, how often the VIX is above
30 or below 15, how many bear markets and corrections a decade brings, the
long-run return, and whether a headline read late still pays. C4a and C4b ask
whether a rule that reads only prices can find an edge real markets do not
have. The other 23 cover the rate indices against real treasury and
corporate bonds, the earnings cycle, value and momentum signals, timing rules
on the published macro data, the cost of size in the book, the real 2020-21
and 2022 macro paths, and the packaged recession. pt-v20 meets all 40.
pt-v19, the previous default, fails 16 of the 40. Its own record has only
the first 17 rows and reads 15 of 17, failing C4a and C4b. On pt-v20 the 2008
replay falls 45 percent against the real 57, the VIX is above 30 on 5.9
percent of days against a real 8.2, and the index returns 6.4 percent a year
over 21 years against a real 6.25. The verdicts ship with the package as
tf.preset_record()["long_run"]. The scripts that graded pt-v20, their
inputs and the grading run's output are in validation/pt-v20/, and
validation/README.md says how to check the grade
in a second or run it again.
Some rows pass near their edges. A timing rule on the published macro data uses 92 percent of its tolerance. The price trough leads the earnings trough in the driven 2020 market by 10 sessions against a real 68. The two-year yield moves 3.87 basis points a day against a real 5.23. A recession wins back 49 percent of its fall in a year against 62 percent in 2009. The index has 2.0 bear markets a decade against a real 1.1.
Two things are still off. The worst month of the 2020 replay is about 19 percent milder than the real one. With the VIX held at 65 the market is 5.1 times as volatile as with it held at 5, against 6.2 times in real markets (pt-v19 5.2).
Each crisis starts in one sector, picked at random. A scenario can pick it for
you with Scenario().hold(epicentre="financial_services").
pt-v20 keeps pt-v19's coefficients where it does not add a mechanism, and those were chosen with a scoring rule over 19 statistics that overlaps the one-year table, so that table helped choose them and cannot also serve as a held-out test. pt-v20's own dials were chosen against the long-run criteria. The held-out checks are the fresh seeds and the fresh set of companies.
These limits are measured and written down. The last column says what would close each one. Anything marked "the next preset" changes the simulation, and a shipped preset never changes, so those wait for a new one.
| limit | what it means | closed by |
|---|---|---|
| horizon | one year is certified. Two years is graded on the two-year panel, and longer runs only by the long-run criteria | bands derived at longer horizons |
| volatility memory | weaker than real at every lag: about a quarter of real at lag 1 and a sixth at lag 20 | the next preset |
| scenario size | a driven scenario moves prices at a quarter to a half of the real size, in the right direction. On the real 2020-21 path the response to the VIX, the credit yield and valuations is 0.27, 0.47 and 0.26 of real AAPL's. Use a scenario to detect a response, and do not read its size as a forecast | the next preset |
| macro crises | an inflation crisis or a policy crisis needs a scenario to drive it | a scenario |
| roster | certification used a sector-balanced roster. Four concentrated sector mixes were measured on pt-v19 only, on the shape rows and for up to two years | the same measurement on pt-v20 |
| opening state | every run on a roster opens at nearly the same VIX (17.66 on the certified roster, whatever the seed), so one-year figures describe years that start calm. For another starting state, run engine.run_days(n) and fork from there |
the next preset |
| overnight gaps | each session opens at the last print. The first tick moves with a standard deviation of 0.67% against 2.0% for the whole day, so a position held overnight behind a stop looks safer than it would live | the next preset |
| intraday | nothing below the 65-minute step is calibrated. One-minute returns have a lag-1 autocorrelation of -0.37 from bid-ask bounce | the next preset |
| slicing a large order | one sweep of the book follows the square-root law, but an order spread over a day costs far less. Buying 10% of a day's volume in 36 slices costs 0.04 of a daily standard deviation, against 0.15 to 0.3 from published studies of such orders, so a schedule optimiser will overstate the value of trading slowly | the next preset |
| agent interaction | an agent's temporary impact barely reaches the tape, its permanent impact is linear and fades on the mispricing's half-life, and volume, depth and the background flow ignore it. No liquidity spiral or predatory trading can arise | the next preset |
tf.envelope.check(horizon_days=...) refuses a question that falls outside
a limit, and the realism envelope
says what each one forbids.
The model has no factor structure beyond each company's beta and sector. There are no style factors, and you cannot supply a covariance matrix. Forced selling is switched off on pt-v20, so a crowded trade unwinding, or any other correlated deleveraging, cannot be represented. The market has one venue, no latency, and no other trader that adapts to you.
Seed determinism
The same seed gives the same market on every platform. Each release builds
for five platforms, runs one fixed simulation on each, and stops if any result
differs. tradefloor ships its own exp, log, pow, sin and cos, so
the system's math library cannot change a result.
pt-v20 became the default in 0.8.5, replacing pt-v19. Every preset from
pt-v1 on can still be selected, and a market with no agent orders in it
replays exactly on its named preset in every later release. Each release
checks that with a digest per shipped preset.
A run with agent orders in it replays exactly on the same release. Across
releases the promise is narrower. 0.8.5 changed how an agent's fills reach
the market, on every preset, so a traded run recorded before 0.8.5 matches up
to its first trade and differs after it. One traded evaluate run has a
digest from 0.8.5, checked on all five platforms: the reference agents on
pt-v20, with their orders, fills and scorecards.
docs/SUPPORT.md
lists what each digest covers.
eng = tf.Engine(seed=42, universe=u, model="pt-v10")
Examples
The twelve numbered examples/ are in reading order, and the test suite runs them:
00-a-year-in-one-market |
Start here: one company, one year, two crises, one chart |
01-first-simulation |
Universe, engine, order book, determinism |
02-evaluating-a-strategy |
Specs, baselines, ranking across seeds |
03-why-did-the-price-move |
The eleven factors that sum to the mispricing's move |
04-how-realistic-is-this |
The realism panel and the limits |
05-training-an-agent |
The Gymnasium environment, and what size costs |
06-execution-and-impact |
TCA and the counterfactual run |
07-research-workflow.py |
A whole study in one file. It takes about forty seconds of CPU and needs tradefloor[arrow] |
08-claude-agent.py |
An LLM agent trading the market through the harness |
09-a-pandemic-shaped-market |
A real 2020-21 macro path, and which fields transmit. Pinned to pt-v12, whose QE channel the repair uses, with the same path on the default, pt-v20, at the end |
10-forking-a-market |
Fork a market, raise the rate in one branch, and compare the futures |
11-scenario-fork.py |
A scenario file applied to one branch of a fork, and what it cost |
Next to them, each self-contained study has its own directory and asks one question. They are in no particular order.
rate-shock/ |
The demo above: checkpoint, fork, +200bps in one branch, compare |
finrobot/ |
The same experiment with a real FinRobot agent |
Agent frameworks
The framework makes the decisions and tradefloor runs the market. Each
adapter in tradefloor.integrations takes one framework through the same
steps: the agent sees the market, decides, its orders fill, and the result is
scored. So two frameworks can be compared on the same market.
| Framework | tradefloor support |
|---|---|
| Plain Python | Generic callable |
| OpenAI Agents SDK | Adapter |
| PydanticAI | Adapter |
| LangGraph | Adapter |
| FinRobot | Existing integration |
pip install "tradefloor[openai-agents]" # or [pydantic-ai], or [langgraph]
A plain Python function needs no extra. FinRobot keeps the finrobot extra
it has always had, and its section below covers the rate-shock experiment
that integration was built for.
Each example runs offline in seconds, with a fixed function in place of the
model, so it needs no API key. A seed replays the market exactly, but a live
model gives a different answer each time. So an adapter records each call
and its answer, and can replay the recording later without the framework or
a key. The four examples are in
examples/integrations/,
which says what each framework contributes and what tradefloor keeps. They
run from a clone of this repository, because they read recorded runs from its
tests/fixtures/.
To test your own model-calling function this way, two arguments of
callable_agent matter. postprocess=to_decision runs
to_decision(raw, payload) on what the function returned, in a live run and
in a replay, so the parsing, risk checks and sizing written there are tested
by every replay. The transcript holds the raw response, and code left inside
the function after the model call runs live only. The callable adapter's
replay key is the payload, which does not include your system prompt, so
pass info=AdapterInfo(framework="callable", instructions_digest=digest(PROMPT))
when you record and when you replay. A replay under a different prompt is
then refused when the adapter is built. Without it the replay runs on the
old answers. The "Plain Python" section of
examples/integrations/README.md
has the whole pattern.
Some things multi-agent research needs are not supported yet. Every agent in a
World starts with the same cash. There is no
multi-agent Gymnasium environment, and the Gymnasium reward is the step's
change in net worth in dollars. Ranking.separation is a sign test with no
effect size, and externalities does not aggregate across seeds.
FinRobot integration
This runs a FinRobot agent in a controlled tradefloor market. It runs a shared history, checkpoints the world, forks it, raises rates by 200bps in one branch, and compares how the same agent responds. It is the rate-shock demo above with the agent swapped and nothing else changed.
git clone https://github.com/simoncoombes/tradefloor
cd tradefloor
python examples/integrations/finrobot/rate_shock.py # replays a real recorded run
By default it replays a recorded FinRobot run, which needs no API key, no
network and no FinRobot install. A plain pip install tradefloor runs it on
any supported Python.
Calling FinRobot itself needs the finrobot extra, which installs only on
Python 3.11. FinRobot declares Python 3.10 and 3.11, and tradefloor needs
3.11 or later. On 3.12 or 3.13, pip stops with "Could not find a version
that satisfies the requirement finrobot>=0.1.5". uv installs it anyway,
outside FinRobot's declared range, and uv pip check then reports the
conflict.
pip install "tradefloor[finrobot]" # Python 3.11 only
python examples/integrations/finrobot/rate_shock.py --live # calls FinRobot
FinRobot is a project of the AI4Finance Foundation, licensed Apache-2.0. This integration is maintained in this repository. AI4Finance has not endorsed it, and it is not part of FinRobot's own interface.
More
To contribute, see CONTRIBUTING.md and RELEASING.md. The main rule is that any change to the simulated trajectory is a breaking change, however small.
Citing tradefloor
Cite the version you ran and name the preset. The same version can run several presets, and results depend on the preset.
@software{tradefloor,
author = {Coombes, Simon},
title = {tradefloor: a deterministic market simulator with a limit order book},
version = {0.8.8},
year = {2026},
url = {https://github.com/simoncoombes/tradefloor},
doi = {10.5281/zenodo.XXXXXXX},
note = {Model preset pt-v20}
}
The DOI is a placeholder. Zenodo will mint one DOI per release once the
archive is switched on; until then, cite the version and the URL and leave
the doi line out. CITATION.cff
carries the same details, and GitHub's "Cite this repository" button reads
it.
In the text, say which model you used, for example: "tradefloor 0.8.8,
preset pt-v20, specified in its docs/MODEL.md". To let a reader rerun a
result, publish its RunManifest: it records the version, preset, seed,
universe, macro state and scenario, and reproduce() stops on a mismatch.
It checks the market and carries no score: its result block holds the
market's digest, the number of days and draws_consumed, and
tf.evaluate and tf.rank write no manifest. A published score has to be
rerun to be checked.
docs/SUPPORT.md
says which release to pin for a long study.
To show a score was not tuned to its seeds, publish tf.commit(seeds, salt)
before the run and the seeds and salt after it. Draw the seeds with
secrets.randbits(64). tf.reveal(commitment, seeds, salt) checks the pair,
and tf.sealed_battery(seeds, salt) builds the fingerprint battery on those
seeds. tf.fingerprint.fingerprint(agent) hashes what an agent ordered
across that battery's fixed markets, so two versions of an agent, with a
changed prompt or in another framework, can be checked for whether they
ordered the same things. It says nothing about which of the two is better.
The default battery is version 2: seven markets, one per shipped scenario,
each run 120 days so a day-50 shock has seventy days after it.
tf.battery(1), the six 60-day markets of earlier releases, still builds,
and a fingerprint compares only against one taken on the same version.
License
tradefloor is licensed under MIT OR Apache-2.0, at your option, which is the usual choice for Rust crates. See LICENSE-MIT and LICENSE-APACHE.
GitHub's sidebar reads Apache-2.0 because its detection picks one file and
stops. So does the sidebar of rust-lang/rust, serde and pyo3, which
carry the same two files. The grant that applies is the dual one, stated in
pyproject.toml, rust/Cargo.toml and this section.
Metadata
Release files for tradefloor 0.8.8
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tradefloor-0.8.8.tar.gz | 1.9 MB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| tradefloor-0.8.8-cp311-abi3-win_amd64.whl | CPython 3.11 | abi3 | Windows x86-64 | Details |
| tradefloor-0.8.8-cp311-abi3-manylinux_2_34_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.34+ x86-64 | Details |
| tradefloor-0.8.8-cp311-abi3-manylinux_2_34_aarch64.whl | CPython 3.11 | abi3 | Linux glibc 2.34+ ARM64 | Details |
| tradefloor-0.8.8-cp311-abi3-macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 11.0+ ARM64 | Details |
| tradefloor-0.8.8-cp311-abi3-macosx_10_12_x86_64.whl | CPython 3.11 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 11.7 MB
Release files / tradefloor-0.8.8.tar.gz
| Download URL | tradefloor-0.8.8.tar.gz |
|---|---|
| Size | 1.9 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8474b0b550b40b5526fbf756389945ba94ebe92706cfec5055b5e565a72c167f
|
|
BLAKE2b-256 checksum How to use checksums |
a9702fb616948f876ca97b3f559cb19fdf88e178a59d6d54cfead18d9b13bfdf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / tradefloor-0.8.8-cp311-abi3-win_amd64.whl
| Download URL | tradefloor-0.8.8-cp311-abi3-win_amd64.whl |
|---|---|
| Size | 1.9 MB |
| Tags | CPython 3.11 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
1a2e4007850a6da6f7041339d161367c48dc8926538669ee47a67e172ddebf14
|
|
BLAKE2b-256 checksum How to use checksums |
1870025e79e247e79f18329121f9ae9984c2a1748f9b17c0d6b4d6ea80e5c73d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / tradefloor-0.8.8-cp311-abi3-manylinux_2_34_x86_64.whl
| Download URL | tradefloor-0.8.8-cp311-abi3-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 2.0 MB |
| Tags | CPython 3.11 Linux glibc 2.34+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
72021aa4b3d461a4bafb9ed1928db82b8157aabdc0aba7604adcf7a088bf6b75
|
|
BLAKE2b-256 checksum How to use checksums |
da219a8276e3203186c19271dad830771b815f7fdb2e65d1b89162e883e561a4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / tradefloor-0.8.8-cp311-abi3-manylinux_2_34_aarch64.whl
| Download URL | tradefloor-0.8.8-cp311-abi3-manylinux_2_34_aarch64.whl |
|---|---|
| Size | 2.0 MB |
| Tags | CPython 3.11 Linux glibc 2.34+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
1b2d7513d38da1ffdf0933ce7e45420fae6cc009d1750f38001a7f05f415b4c3
|
|
BLAKE2b-256 checksum How to use checksums |
a3e6cc2feccb6bc7e4f17c41518e00bfe7615a10d6073a810873c5a5fcd7bf20
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / tradefloor-0.8.8-cp311-abi3-macosx_11_0_arm64.whl
| Download URL | tradefloor-0.8.8-cp311-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.9 MB |
| Tags | CPython 3.11 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
8fd03f0cfae4bb593729cbee8529f27149416610021437343edef38d19463787
|
|
BLAKE2b-256 checksum How to use checksums |
c2d43b7d18537f9c74d156af5ee0b90e3f9d253b2ec0399d789e401302378c90
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / tradefloor-0.8.8-cp311-abi3-macosx_10_12_x86_64.whl
| Download URL | tradefloor-0.8.8-cp311-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 2.0 MB |
| Tags | CPython 3.11 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
baa4a2c390923b1c43ca8c7f7de0dcab527d9248990837eef348400d9e076158
|
|
BLAKE2b-256 checksum How to use checksums |
a40476034fdf508f04be3955120593e52db828371570e22993f878dfb6bef709
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency log