This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
position-sizing
Traduce un presupuesto de riesgo a una cantidad que el exchange acepte, sin pasarse nunca del riesgo.
pip install position-sizing
El problema
El cálculo parece trivial —riesgo / distancia_al_stop— y no lo es, porque el
resultado hay que hacerlo caber en las restricciones del mercado. Ahí es donde se
pierde dinero, y de dos formas silenciosas.
Redondear hacia arriba. Este patrón está en incontables bots:
cantidad = max(1, int(cantidad_teorica / contract_size))
Si la cantidad teórica sale 0.1 contratos, int() la trunca a 0 y
max(1, ...) fuerza uno. Acabas de abrir una posición que arriesga diez
veces lo autorizado. Con saldo pequeño o stop ancho ocurre siempre, y sin
avisar.
Ignorar el nocional mínimo. La orden se rechaza al llegar al exchange, el bot lo registra como error de red, y nadie se entera de que esa señal nunca se operó.
Qué hace esta librería
- Redondea siempre hacia abajo. Pasarse del presupuesto se paga con dinero; quedarse corto solo cuesta rendimiento. El error es asimétrico y el redondeo también.
- Se niega a operar cuando el mínimo del mercado no cabe en el riesgo — y dice cuánto saldo haría falta para que cupiera.
- Respeta
contractSize, escalón de cantidad, mínimos, máximos y nocional mínimo. - Cuenta comisiones de ida y vuelta: con un stop ajustado son la mitad del riesgo real.
- Distingue margen de riesgo: apalancarse cambia lo que puedes abrir, no lo que pierdes si salta el stop.
Uso
from decimal import Decimal
from position_sizing import MarketSpec, size_for_risk
spec = MarketSpec(
amount_step=Decimal("0.001"), # escalón de cantidad
min_amount=Decimal("0.001"),
min_notional=Decimal("5"), # valor mínimo de la orden
)
r = size_for_risk(
balance=Decimal("1000"),
risk_fraction=Decimal("0.01"), # arriesgar el 1%
entry=Decimal("50000"),
stop=Decimal("49000"),
spec=spec,
fee_rate=Decimal("0.0005"), # 0,05% por lado
)
if r.ok:
exchange.create_order(symbol, "market", "buy", float(r.quantity))
else:
log.warning("sin operar: %s", r.reason)
# -> "la cantidad mínima del mercado arriesga más de lo presupuestado;
# harían falta 5000.00 de saldo"
size_for_risk devuelve siempre un Sizing, nunca None:
| Campo | Qué es |
|---|---|
quantity |
Cantidad a enviar. Cero si se rechazó |
notional |
precio × cantidad × contract_size |
risk_amount |
Pérdida si salta el stop, comisiones incluidas |
risk_budget |
Lo que se pidió arriesgar. risk_amount nunca lo supera |
rejection |
None, o el motivo tipado |
min_balance_required |
Saldo necesario para superar el rechazo |
.ok / .reason |
Booleano y explicación lista para un log |
Con ccxt
from position_sizing import spec_from_ccxt, size_for_risk
spec = spec_from_ccxt(exchange.market("BTC/USDT:USDT"))
r = size_for_risk(balance=bal, risk_fraction=Decimal("0.01"),
entry=precio, stop=sl, spec=spec)
El adaptador es el único punto que sabe de ccxt. Resuelve además una
inconsistencia real: unos exchanges dan precision.amount como escalón (0.001)
y otros como número de decimales (3). Confundirlos hace que toda cantidad salga
mal.
Dos decisiones de diseño
Decimal, no float. El bug de arriba nace de un truncamiento. Con decimal y
redondeo explícito, la dirección es una decisión y no un accidente del tipo.
Función pura: recibe una MarketSpec, no un exchange. Se prueba sin red,
sirve para cualquier exchange y —lo que más importa— calcula igual en backtest
que en producción. Un backtest que asume posiciones fraccionarias que el mercado
nunca aceptaría infla el retorno; con la misma función en ambos lados, esa mentira
desaparece.
Alcance
Esto dimensiona órdenes. No decide cuándo operar, ni dónde poner el stop, ni en qué dirección. Es aritmética sobre restricciones de exchange, no una estrategia.
Licencia
Apache-2.0 · Copyright 2026 Juan Carlos Isaza Arenas
Metadata
Release files for position-sizing 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| position_sizing-0.1.0.tar.gz | 14.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| position_sizing-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 27.1 kB
Release files / position_sizing-0.1.0.tar.gz
| Download URL | position_sizing-0.1.0.tar.gz |
|---|---|
| Size | 14.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fd89169607e676342700c2a59eeb4f3f29d2f88e5050d7d84b5781073fc8f964
|
|
BLAKE2b-256 checksum How to use checksums |
db8d21a5ca8ec1ec12a987653c2dee4af4fbc0d0ffcf1e6402d8b9ceee36952e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 18, 2026.
Transparency logRelease files / position_sizing-0.1.0-py3-none-any.whl
| Download URL | position_sizing-0.1.0-py3-none-any.whl |
|---|---|
| Size | 12.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d948438cae02ecc1a03ce0730fff0dfe18dd7e8a4112ebe34249c98560161a27
|
|
BLAKE2b-256 checksum How to use checksums |
03f105dcfe3ef0d6f547e085cd00198a9d03228608809826b8123400f04fd64c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 18, 2026.
Transparency log