primary-api
Python library for connecting to the Primary API (Matba Rofex exchange). Fork/refactor of pyRofex. Provides REST and WebSocket clients for market data, order management, and account reports.
Stack: Python 3.8+, requests, simplejson, websocket-client, pydantic
Installation
pip install primary-api
Quick Start
from primary_api import PrimaryApiClient, Environment, MarketDataEntry
client = PrimaryApiClient(
user="username",
password="password",
account="account123",
environment=Environment.REMARKET
)
# REST: get market data
md = client.get_market_data("DLR/MAY26", [MarketDataEntry.LAST])
print(md)
# Market data handler
def on_md(msg):
print(msg)
# WebSocket: subscribe to market data
sub = client.market_data_subscription(
tickers=["DLR/MAY26"],
entries=[MarketDataEntry.BIDS, MarketDataEntry.OFFERS],
handler=on_md
)
client.wait_for_interrupt()
Models
You can use primary-api-models built on Pydantic BaseModel for automatic responses and messages validations.
pip install primary-api-models
For docs, visit https://pypi.org/project/primary-api-models/
Configuration
Environment
Two environments are available via the Environment enum:
| Environment |
Description |
Environment.REMARKET |
Remarkets (testing/simulation) — proprietary = "PBCP" |
Environment.LIVE |
Live production — proprietary = "api" |
Production environment
from primary_api import PrimaryApiClient, Environment
client = PrimaryApiClient(
username="matriz-username",
password="matriz-password",
account="matriz-account",
rest_url="https://api.your-broker.xoms.com.ar",
ws_url="wss://api.your-broker.xoms.com.ar",
environment=Environment.LIVE
)
REST API
Market Data
| Method |
Description |
get_segments() |
Get all available market segments |
get_all_instruments() |
Get all instruments |
get_detailed_instruments() |
Get detailed instrument list |
get_instrument_details(ticker, market) |
Get details for a specific instrument |
get_market_data(ticker, entries, depth, market) |
Get market data (bids, offers, last price, etc.) |
Orders
| Method |
Description |
send_order(ticker, size, order_type, side, ...) |
Send a new order |
cancel_order(client_order_id, proprietary) |
Cancel an existing order |
get_order_status(client_order_id, proprietary) |
Check order status |
get_all_orders_status(account) |
Get all orders for an account |
Account
| Method |
Description |
get_account_position(account) |
Get account position |
get_detailed_position(account) |
Get detailed position |
get_account_report(account) |
Get account report |
get_trade_history(ticker, start_date, end_date, market) |
Get trade history |
Example: Sending an Order
from primary_api import Side, OrderType, TimeInForce, Market
order = client.send_order(
ticker="DLR/MAY26",
size=10,
order_type=OrderType.LIMIT,
side=Side.BUY,
market=Market.ROFEX,
time_in_force=TimeInForce.DAY,
price=850.50,
)
WebSocket Subscriptions
init_websocket_connection
Set up all handlers and establish the WebSocket connection in one call (pyRofex compatible):
def on_market_data(msg):
print(msg)
def on_order_report(msg):
print(msg)
def on_error(msg):
print(f"Error: {msg}")
def on_exception(e):
print(f"Exception: {e}")
client.init_websocket_connection(
market_data_handler=on_market_data,
order_report_handler=on_order_report,
error_handler=on_error,
exception_handler=on_exception,
)
# Handlers are already set — subscribe without passing handler
sub = client.market_data_subscription(tickers=["DLR/MAY26"], entries=[...])
Market Data Subscription
def handle_market_data(message):
print(message)
sub = client.market_data_subscription(
tickers=["DLR/MAY26", "DLR/JUN26"],
entries=[
MarketDataEntry.BIDS,
MarketDataEntry.OFFERS,
MarketDataEntry.LAST,
],
depth=5,
handler=handle_market_data
)
print(sub.count()) # 2 tickers
print(sub.active) # True
print(sub.to_dict()) # full details (handler is no longer None)
print(sub.to_dict()["handler"]) # the handler function
sub.unsubscribe() # stop receiving updates (also removes the handler)
Order Report Subscription
def handle_order_report(message):
print(message)
sub = client.order_report_subscription(
handler=handle_order_report
)
sub.unsubscribe() # also removes the handler
WebSocket Lifecycle
- First
connect(): raises ApiException if the endpoint is unreachable.
- Auto-reconnect: after a successful connection, if the WebSocket drops, it reconnects automatically in a background thread. All active subscriptions are re-sent on reconnect.
- Cleanup: call
client.close_websocket() to stop the reconnection loop.
- Handler cleanup:
sub.unsubscribe() removes both the subscription and its associated handler from the active list.
Enums Reference
| Enum |
Values |
Environment |
REMARKET, LIVE |
Market |
ROFEX |
MarketSegment |
DDF, DDA, DUAL, U_DDF, U_DDA, U_DUAL, MERV |
Side |
BUY, SELL |
OrderType |
LIMIT, MARKET, MARKET_TO_LIMIT |
TimeInForce |
DAY, ImmediateOrCancel, FillOrKill, GoodTillDate |
MarketDataEntry |
BIDS, OFFERS, LAST, OPENING_PRICE, CLOSING_PRICE, SETTLEMENT_PRICE, HIGH_PRICE, LOW_PRICE, TRADE_VOLUME, OPEN_INTEREST, INDEX_VALUE, TRADE_EFFECTIVE_VOLUME, NOMINAL_VOLUME, ACP, TRADE_COUNT |
CFICode |
STOCK, BOND, CALL_STOCK, PUT_STOCK, FUTURE, PUT_FUTURE, CALL_FUTURE, CEDEAR, ON |
Tests development
Environment variables (for testing)
Create a .env file:
CL_USERNAME=your_user
CL_PASSWORD=your_pass
CL_ACCOUNT=your_account
CL_ENVIRONMENT=REMARKET
CL_API_HTTPS=https://api.remarkets.primary.com.ar/
CL_API_WSS=wss://api.remarkets.primary.com.ar/