Skip to content
python.financial
Platform
Trading bot framework
License
LGPL-3.0
Pricing
Open-source package with separate hosted-service terms
Live trading
Supported through exchange connectors, subject to current compatibility
Best for
Evaluating or maintaining existing Blankly code after testing each dependency

Blankly combines an open-source Python package with hosted services. Its goal is to move the same strategy code from backtesting to paper and live trading. The API is appealing, but it is not a low-risk default for a new live bot. The package and repository have seen little recent work, and the hosted product still calls itself a beta.

The safe way to assess Blankly is to treat the Python package, exchange connectors, and cloud platform as three separate dependencies. Verify each one against a paper account and current vendor API before trusting the "backtest to live" workflow.

Is Blankly still maintained?

Part What is publicly available What it means for a user
Python package PyPI lists 1.18.25b0, released July 23, 2023, as the latest version. It is marked beta. Pin the version and test it with your Python, pandas, exchange SDKs, and authentication flow.
Source repository The latest official repository commit is a December 30, 2024 packaging-metadata change that adds Python 3.11 and 3.12 classifiers. A newer classifier does not replace a package release or demonstrate that every connector works.
Hosted platform Blankly's status page called Blankly Slate an open beta at its July 7, 2026 update. The main site presents a waitlist, and the pricing page labels plans "Coming Soon." Do not infer general availability, service levels, or a payable production plan from the posted feature and price tables. Ask Blankly for current access terms.
Documentation Package docs and the repository remain online, but several public pages retain old product and integration language. Use docs to understand the API, then validate claims against current code and third-party APIs.

This evidence supports "limited maintenance," not the previous "active" label. Blankly may still work for a particular connector and environment. The public artifacts do not establish broad production readiness.

How is the package designed?

The package wraps exchange and broker operations behind common interface classes. A Strategy registers scheduled or price-driven callbacks, then strategy.backtest() replays historical data while strategy.start() runs the callbacks against a configured live interface. The official strategy reference documents the shared callback model, and the repository shows the intended one-line switch between backtest and live modes.

Shared strategy functions reduce duplicate application code. They do not make simulation and production equivalent. Historical bars, a paper account, and a live venue can differ in timestamps, symbol rules, rate limits, partial fills, order rejection, fees, funding, borrow availability, and outages. Treat backtesting, paper trading, and live trading as separate validation stages even when they call the same function.

Can you run a Blankly backtest without exchange credentials?

Yes. PriceReader and KeylessExchange provide a useful local compatibility test without contacting an exchange or placing a live order. Pin the older scientific stack explicitly. On September 19, 2026, an unconstrained installation selected NumPy 2.4.6 and failed during import blankly because the released newnewtulipy wheel used an incompatible NumPy 1.x binary interface. The following combination imported and ran locally:

python -m pip install "blankly==1.18.25b0" "numpy==1.26.4" "pandas==2.2.3"

Blankly normally creates configuration files through blankly init. For a credential-free test, save this minimal settings.json beside the script:

{
  "settings": {
    "use_sandbox_websockets": false,
    "websocket_buffer_size": 10000,
    "test_connectivity_on_auth": false,
    "auto_truncate": false,
    "global_shorting": false,
    "simulate_margin": true,
    "keyless": {"cash": "USD"}
  }
}

Also save a minimal backtest.json:

{
  "price_data": {"assets": []},
  "settings": {
    "use_price": "close",
    "smooth_prices": false,
    "GUI_output": false,
    "show_tickers_with_zero_delta": false,
    "save_initial_account_value": true,
    "show_progress_during_backtest": false,
    "cache_location": "./price_caches",
    "continuous_caching": false,
    "resample_account_value_for_metrics": "1d",
    "quote_account_value_in": "USD",
    "ignore_user_exceptions": false,
    "risk_free_return_rate": 0.0,
    "benchmark_symbol": null
  }
}

The script below passes four synthetic daily bars to the local price reader, buys one unit on the first callback, applies a 0.1% taker fee, and inspects the simulated account. The integer casts are intentional because pandas returns NumPy integer scalars. The end time is one interval after the final input row because this Blankly path subtracts one resolution when choosing its inclusive data range.

import pandas as pd

import blankly
from blankly.data import PriceReader


prices = pd.DataFrame(
    {
        "time": [1_735_689_600, 1_735_776_000, 1_735_862_400, 1_735_948_800],
        "open": [100.0, 101.0, 102.0, 103.0],
        "high": [101.0, 102.0, 103.0, 104.0],
        "low": [99.0, 100.0, 101.0, 102.0],
        "close": [100.0, 101.0, 102.0, 103.0],
        "volume": [1_000, 1_000, 1_000, 1_000],
    }
)


def initialize(symbol, state):
    state.variables["bought"] = False


def on_price(price, symbol, state):
    if not state.variables["bought"]:
        state.interface.market_order(symbol, side="buy", size=1)
        state.variables["bought"] = True


reader = PriceReader(prices, "TEST-USD")
exchange = blankly.KeylessExchange(
    price_reader=reader,
    maker_fee=0.001,
    taker_fee=0.001,
    settings_path="settings.json",
)
strategy = blankly.Strategy(exchange)
strategy.add_price_event(
    on_price,
    symbol="TEST-USD",
    resolution="1d",
    init=initialize,
)
result = strategy.backtest(
    start_date=int(prices.time.iloc[0]),
    end_date=int(prices.time.iloc[-1] + 86_400),
    initial_values={"USD": 1_000},
    settings_path="backtest.json",
)

fills = result.trades["executed_market_orders"]
account = result.get_account_history()
print("market fills:", len(fills))
print("fill price:", fills[0]["executed_price"])
print("final TEST:", account["TEST"].iloc[-1])
print("final value:", round(account["Account Value (USD)"].iloc[-1], 2))

The relevant result lines from the exact displayed code were:

market fills: 1
fill price: 100.0
final TEST: 0.999
final value: 1002.9

This is an engine-wiring test, not a profitable strategy. Its rising prices are constructed, the order fills at the same close delivered to the callback, and no spread or slippage is modeled. It verifies local data ingestion, event dispatch, one paper fill, the configured taker fee, and account valuation. It says nothing about current exchange authentication, downloads, WebSockets, rejected orders, latency, liquidity, or connector reliability.

What does Blankly aim to provide?

  • One strategy interface. Scheduled and price-event callbacks can target backtest, paper, sandbox, or live modes.
  • Several asset and venue adapters. The package includes exchange and brokerage classes plus WebSocket-oriented data handling.
  • Local backtesting. Strategies can replay price data, track an account, export results, and calculate metrics.
  • Deployment services. The hosted product describes container deployment, logs, monitoring, team workflows, backtest comparison, and reporting.
  • An open-source core. The Python repository uses the GNU Lesser General Public License v3.

These are design capabilities, not a current compatibility matrix. The repository README still labels a long list of integrations as working or planned even though the latest PyPI beta predates several years of exchange API changes. Test only the venue, asset type, order types, and data path you intend to use.

What should you test before adopting it?

Package compatibility

Create a clean environment, pin Blankly and every transitive dependency, then run the repository tests and a minimal local backtest. The verified example above needs a NumPy 1.x pin, and pandas 2.2 emits deprecation warnings from Blankly's account-history concatenation path. Importing the package is not enough. Exercise serialization, historical-data downloads, plots, metrics, and the exact Python version used for deployment.

Exchange behavior

Use a sandbox or paper account to test authentication, clock drift, symbol formatting, precision and minimum-size rules, rate limits, WebSocket reconnection, duplicate events, order cancellation, partial fills, and position reconciliation. Confirm that retries cannot submit the same order twice.

Backtest assumptions

Inspect how Blankly obtains and aligns historical data, when a callback observes a bar, which price fills an order, and how fees are charged. Add slippage, transaction costs, funding, and liquidity limits that match the venue. A common interface does not supply realistic assumptions automatically.

Operational ownership

Decide who owns alerting, secret rotation, dependency updates, incident response, and recovery from a lost data stream or ambiguous order state. For hosted deployment, obtain current documentation for regions, backups, service levels, key storage, data retention, export, and account deletion. The marketing site alone is not sufficient security or availability evidence.

What are the main risks?

  • Stale released code. The latest installable version on PyPI is a July 2023 beta. Exchange and broker APIs change independently of Blankly.
  • Unclear platform availability. Public pages simultaneously show an open beta, a waitlist, posted plans, and "Coming Soon" labels. Availability and pricing require direct confirmation.
  • Connector drift. A connector's presence in source or a README does not prove current authentication, market-data, or order compatibility.
  • Simulation-to-live differences. Reusing callbacks removes some code duplication, but it does not remove the semantic gap between historical replay and a live matching engine.
  • Secret exposure. blankly init creates local configuration including keys.json. Keep credentials out of version control, scope permissions narrowly, and use the deployment environment's secret manager.
  • Limited independent verification. No benchmark or production reliability evidence was found that would support performance, accuracy, uptime, or scaling claims.

Should you use Blankly?

Use it only after a focused proof of concept confirms the package and connector you need. Existing users may reasonably maintain a pinned deployment if they can test and patch it. For a new system, compare Blankly with actively released alternatives and price the engineering work required to own stale integrations. Do not place live capital behind a connector merely because an old compatibility table marks it as supported.

Choose which optional services may run. You can change these settings at any time.