profitdll-wrapper
High-performance, idiomatic, typed, and memory-safe Python wrapper for ProfitDLL (Nelogica's native API).
English | Português (BR)
[!NOTE] Status: v0.4.1 — P0 (Trades), P1 (Price Depth), P2 (Order Routing & Custody) and the ingestion stack validated against the vendor simulator / real DLL. Full test suite with 287 unit and ABI contract tests (80%+ code coverage), running under
mypy --strict,ruff, andpytest. Pure Enqueue architecture immune to C ↔ GIL reentrancy crashes.
[!WARNING] Independent, community-driven project — not affiliated with Nelogica.
profitdll-wrapperis developed and maintained by the community. Profit, ProfitDLL, and related names are products and trademarks of Nelogica, which does not endorse, sponsor, or support this project. The proprietary DLL is not distributed here.No financial responsibility. This software can place real orders with real money when connected to a real brokerage account. It is provided "as is", without warranty of any kind, for research and educational purposes. The authors accept no liability for financial losses, missed or duplicated orders, incorrect or delayed data, or any trading outcome. Validate everything on a simulator/demo account first — you are solely responsible for the orders your code sends.
What is profitdll-wrapper
profitdll-wrapper is a modern Python wrapper for Nelogica's ProfitDLL — a native C/Pascal API (stdcall calling convention, featuring raw memory pointers and callback threads on a dedicated C ConnectorThread).
It abstracts away low-level ctypes complexity and provides:
- Idiomatic API: Context managers (
with), immutable dataclasses (Trade,PriceLevel,PriceBookSnapshot,DailyCandle,Order,Position,Account), strictenumtypes, and comprehensive type hints; - Order Routing & Custody: Limit orders (
send_buy_order,send_sell_order), market orders (send_market_buy,send_market_sell), order cancellations (cancel_order,cancel_all_orders), and real-time custody position tracking (get_position,Event.ORDER,Event.POSITION); - Pure Enqueue Architecture: C callbacks only enqueue lightweight positional payloads in microseconds without reentrant ctypes calls, preventing deadlocks and segfaults under high market volume;
- Fault Tolerance & Safety: User exception isolation in event handlers ensures callback failures never crash the native DLL process or interrupt data streams;
- Zero Runtime Dependencies: Built strictly using the Python standard library (
dependencies = []).
Detailed architectural and API documentation is published at https://diogojrdev.github.io/profitdll-wrapper/:
| Document | Content |
|---|---|
| Architecture | Layer design, abstraction patterns, and thread-safety invariants |
| API Surface | Native ProfitDLL function mapping and ABI audit |
| Ingest | Historical data ingestion: sinks, schema, and the profitdll-ingest CLI |
Live Showcase
Experience real-time market data streaming, order book depth, and historical ingestion in your terminal:
⚡ Real-Time Terminal TUIs
Times & Trades Tape & Aggression Gaugeexamples/10_times_and_trades_tui.py |
Full Level-2 Order Book (DOM)examples/11_order_book_tui.py |
[!TIP] Both TUIs run anywhere (cross-platform, even without ProfitDLL credentials or Windows) via synthetic demo mode:
uv run --extra tui python examples/10_times_and_trades_tui.py --demo uv run --extra tui python examples/11_order_book_tui.py --demo
⚡ High-Speed Historical Ingestion (profitdll-ingest)
Download tens of thousands of tick-by-tick trades in seconds directly to SQLite, Parquet, CSV, or PostgreSQL/TimescaleDB:
Installation
Install from PyPI with pip:
pip install profitdll-wrapper
Or, in a project managed with uv:
uv add profitdll-wrapper
[!TIP] The distribution name is
profitdll-wrapper(hyphen), but the import name isprofitdll_wrapper(underscore):from profitdll_wrapper import Event, ProfitClient
Requirements: Python 3.10+ on Windows (the native ProfitDLL is a Windows stdcall library).
Optional extras
The core package has zero runtime dependencies. Ingest backends are opt-in:
pip install "profitdll-wrapper[postgres]" # PostgreSQL / TimescaleDB sink (psycopg)
pip install "profitdll-wrapper[parquet]" # Parquet sink (duckdb)
pip install "profitdll-wrapper[all]" # everything
The Native (Proprietary) DLL
Nelogica's ProfitDLL is proprietary and is not bundled with this package. To connect to Nelogica servers or simulator:
- Set the environment variable
PROFITDLL_PATH=/path/to/ProfitDLL.dll(orProfitDLL64.dll), or; - Place the DLL inside a
dll/directory in your working directory. - Create a
.envfile in your working directory with your simulator credentials:ACTIVATION_KEY=your_key USER=your_username PASSWORD=your_password
The DLL directory must also contain the vendor runtime data (broker routing files); keep it out of version control.
Quickstart
1. Real-Time Trade Ticks (P0)
from profitdll_wrapper import Event, ProfitClient, Trade
with ProfitClient(
activation_key="KEY...",
user="USER...",
password="PASSWORD...",
mode="market_data", # "market_data" or "routing"
# broker_id=15003, # optional; defaults to BROKER in the .env file
) as client:
client.subscribe("WDOFUT", exchange="F")
@client.on(Event.TRADE)
def on_trade(trade: Trade) -> None:
print(
f"{trade.asset.ticker} | Price: {trade.price:.2f} x{trade.quantity} | Aggressor: {trade.trade_type}"
)
client.run() # blocks keeping event loop active (Ctrl+C to exit)
2. Price Book / Price Depth & Thread-Safe Queries (P1)
from profitdll_wrapper import Event, PriceLevel, ProfitClient
with ProfitClient(
activation_key="KEY...",
user="USER...",
password="PASSWORD...",
mode="market_data",
) as client:
client.subscribe_price_depth("PETR4", exchange="B")
@client.on(Event.PRICE_LEVEL)
def on_level(level: PriceLevel) -> None:
print(
f"[{level.update_type.name}] {level.side.name} pos={level.position} qty={level.quantity}"
)
# Thread-safe level query outside of callback
# top_buy = client.get_price_group("PETR4", side=0, position=0, exchange="B")
client.run()
Practical Examples
Explore the examples/ directory — eleven ready-to-run scripts, from market data streaming to trading bots:
| Script | Category | Description | Mode |
|---|---|---|---|
01_subscribe_ticker.py |
MVP / Quotes | Minimal real-time trade tick streaming | market_data |
02_price_depth.py |
Price Book | Order book depth updates and snapshots | market_data |
03_live_smoke.py |
Smoke Test | Self-contained live validation with report | market_data / routing |
04_send_order.py |
Routing | Limit buy/sell orders and execution tracking | routing |
05_market_data_streamer.py |
Data Streamer | Trades, V2 book, close prices → CSV / pandas DataFrame | market_data |
06_trading_bot_sample.py |
Trading Bot | Full bot blueprint: state machine, order manager, Stop Loss & Take Profit | routing |
07_watchdog_and_reconciliation.py |
Infra / Reconciliation | DLL health watchdog, auto-reconnect, daily position reconciliation | routing |
08_corporate_actions_and_history.py |
History & Corporate Actions | Tick-by-tick history download and corporate actions | market_data |
09_historical_to_database.py |
History → Database | Historical trades to SQLite via the ingest subpackage |
market_data |
10_times_and_trades_tui.py |
TUI / Market Data | Native-style Times & Trades: summary bar, mirrored buyer/seller tape, quantity bars and pressure gauge (rich, --demo anywhere) |
market_data |
11_order_book_tui.py |
TUI / Market Data | Full Level-2 DOM with native summary bar, mirrored bid/ask sides and proportional quantity bars (rich, --demo anywhere) |
market_data |
12_list_accounts.py |
Custody | Enumerates every trading account (and sub-account) for the login, validating the .env account |
routing |
Historical Data → Database
The profitdll-ingest command downloads tick-by-tick historical trades (and optional daily candles) via ProfitDLL and persists them to a configurable backend. SQLite and CSV are built in (zero extra dependencies); Parquet and PostgreSQL/TimescaleDB ship as optional extras.
Quickstart (SQLite, zero deps)
pip install profitdll-wrapper
profitdll-ingest --ticker VALE3 --start 01/01/2026 --end 31/01/2026
# -> writes to ./profit_data.db
PostgreSQL / TimescaleDB via Docker
The database runs in Docker; the ingestion script runs on the Windows host (where the native DLL lives). Grab docker-compose.yml and .env.example from the repository.
cp .env.example .env # set TIMESCALE_PASSWORD
docker compose up -d timescaledb
pip install "profitdll-wrapper[postgres]"
profitdll-ingest --ticker VALE3,PETR4 --exchange B,B \
--start 01/01/2026 --end 31/01/2026 \
--to postgres \
--db-url postgresql://profit:secret@localhost:5432/profit
Programmatic API
from profitdll_wrapper import ProfitClient
from profitdll_wrapper.ingest import create_sink, ingest_history
sink = create_sink("sqlite", db_url="profit.db")
with ProfitClient(activation_key="...", user="...", password="...", mode="market_data") as client:
stats = ingest_history(
client=client,
sink=sink,
tickers=[("VALE3", "B")],
start_date="01/01/2026 09:00:00",
end_date="31/01/2026 18:00:00",
)
print(f"{stats.trades_written} trades persisted in {stats.elapsed_seconds:.1f}s")
sink.close()
Multiple windows in one session (e.g. each trading day with its own session
hours): use ingest_windows — it keeps a single request in flight, completes
each one via the DLL's progress callback (Event.HISTORY_PROGRESS, progress
reaching 100), and discards trades outside the current request's window:
from profitdll_wrapper.ingest import ingest_windows
with ProfitClient(activation_key="...", user="...", password="...") as client:
stats = ingest_windows(
client=client,
sink=sink,
tickers=[
("PETR4", "B", "27/08/2026 10:00:00", "27/08/2026 16:55:00"),
("PETR4", "B", "02/09/2026 10:00:00", "02/09/2026 16:55:00"),
],
)
for req in stats.tickers:
print(req.ticker, req.trades_written, "completed_by_progress =", req.completed_by_progress)
See the ingestion guide for schema details, hypertables, idempotency, tuning, and the multi-window contract, and examples/09_historical_to_database.py for a runnable end-to-end example.
Limitations
- The native DLL supports a single lifecycle per process. After
disconnect()(which callsDLLFinalize), constructing a newProfitClientin the same process raisesRuntimeError("ProfitDLL was already finalized in this process; ...")immediately — the DLL's global state survivesDLLFinalize(the Windows loader ref-counts the module) and a re-initialization never completes its market-data connection. The vendor manual documents no re-initialization support. Run one session per subprocess when you need multiple sequential sessions (the same pattern the integration tests use). ingest_historyis one-window-per-run by contract: every ticker sharesstart_date/end_dateand all requests are fired up front. The historical trade event carries no window attribution, so stacking runs with different windows on one session can contaminate tapes with late responses. Useingest_windowsfor per-ticker windows.- History is capped at 30 days by the server: requests whose start date is
older than 30 days (server date) are rejected with
HistoryPeriodLimitError. Split longer backfills into ≤30-day windows.
Development & Testing
This project uses uv for dependency management and tooling.
git clone https://github.com/diogojrdev/profitdll-wrapper.git
cd profitdll-wrapper
uv sync # creates virtualenv and installs dev dependencies
uv run pytest # runs full test suite (225 unit & ABI tests)
uv run ruff check . # runs linter
uv run ruff format --check . # checks code formatting
uv run mypy --strict src # checks strict type annotations
Integration Testing with Real Native DLL
Integration tests running against Nelogica's real DLL and simulator use the @pytest.mark.integration marker:
uv run pytest -m integration
Feedback
If profitdll-wrapper helps you trade on B3, consider giving it a ⭐ and opening an issue with feedback — early-stage issues are gold for prioritizing the roadmap.
License
MIT. Nelogica's native ProfitDLL is proprietary software and is not included in this repository.
This is an independent, community-maintained project with no affiliation to Nelogica, and it is provided with no financial liability for trading losses — see the disclaimer at the top.
Contributing
Contributions are welcome! See CONTRIBUTING.md for development guidelines.
Release files for profitdll-wrapper 0.4.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| profitdll_wrapper-0.4.1.tar.gz | 1.7 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| profitdll_wrapper-0.4.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.8 MB
Release files / profitdll_wrapper-0.4.1.tar.gz
| Download URL | profitdll_wrapper-0.4.1.tar.gz |
|---|---|
| Size | 1.7 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2fb02b8d365d85b19affaa23e0a04b81b710e4eb3aa5b042ef89a10a09d914a4
|
|
BLAKE2b-256 checksum How to use checksums |
7614be97b17b7c4fe0b703433b7e9f17de1ede0f74f6c3f554d5e39b52d031fd
|
| 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 Sep 3, 2026.
Transparency logRelease files / profitdll_wrapper-0.4.1-py3-none-any.whl
| Download URL | profitdll_wrapper-0.4.1-py3-none-any.whl |
|---|---|
| Size | 94.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
99b08e3ed6d183aaabe3185d2c0534008ea93eff753a9f314f956725db8dfc42
|
|
BLAKE2b-256 checksum How to use checksums |
b51078a30aa3c707526476b016753ffbdc945974078b6348239f956ee62834b3
|
| 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 Sep 3, 2026.
Transparency log