Primary — Trading API de Matba ROFEX

SkillCommerce & finance

Trading API for Primary (Matba ROFEX): futures, options, stocks, bonds. Orders, positions, account, market data.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Primary — Trading API de Matba ROFEX skill

What this skill tells your AI

The instructions your AI receives, as published by gauss314/skills in skills/primary/SKILL.md and read by ahel’s review.

API para operar en el Mercado Argentino de Futuros y Opciones (Matba ROFEX) a través de Primary Trading Platform (PTP). Soporta futuros (dólar, soja, trigo, maíz, índices), opciones sobre futuros, acciones, bonos y CEDEARs.

Base URL: https://api.remarkets.primary.com.ar

Docs: github.com/matbarofex — repositorio oficial con ejemplos open source.


Autenticación

Obtener Credenciales

EntornoURLDescripción
REMARKET (demo)remarkets.primary.venturesCrear cuenta gratis para paper trading
LIVE (producción)Contactar a mpi@primary.com.arSolicitar acceso al equipo MPI

Una vez creada la cuenta en REMARKET, tendrás:

  • Usuario: el que registraste
  • Password: el que configuraste
  • Account: tu número de cuenta (suele ser REM + últimos dígitos del usuario)

Obtener Token

import requests

r = requests.post("https://api.remarkets.primary.com.ar/auth/getToken",
    headers={"X-Username": tu_usuario, "X-Password": tu_password})

token = r.headers["X-Auth-Token"]

El token se envía en adelante como header X-Auth-Token en todos los requests.

⚠️ NUNCA hardcodear credenciales. Usar variables de entorno o parámetros CLI.

import os
TOKEN = os.getenv("PRIMARY_TOKEN")  # Opcional: cachear token
USER = os.getenv("PRIMARY_USER")
PASS = os.getenv("PRIMARY_PASSWORD")
ACCOUNT = os.getenv("PRIMARY_ACCOUNT")  # Ej: 12345 o REM12345

Renew Token

Si recibís un 401, el token expiró. Renovalo con un nuevo POST a /auth/getToken.


Segmentos

El mercado se organiza en segmentos (ruedas de negociación). Cada instrumento pertenece a un segmento.

SegmentoDescripción
DDFDerivados Financieros (futuros de dólar, índices)
DDADerivados Agropecuarios (soja, trigo, maíz)
DUALInstrumentos listados en ambas divisiones
MERVMercados externos a Matba ROFEX (BYMA)
MAEMercado Abierto Electrónico
TESTAmbiente de pruebas
U-DDF, U-DDA, U-DUAL, U-FIN, U-COMM, U-STOCKSub-segmentos de usuarios
TIVA, AVSOtros segmentos

Listar Segmentos

GET https://api.remarkets.primary.com.ar/rest/segment/all
r = requests.get("https://api.remarkets.primary.com.ar/rest/segment/all",
    headers={"X-Auth-Token": token})
print(r.json()["segments"])

Respuesta:

{"status":"OK","segments":[
  {"marketSegmentId":"DDF","marketId":"ROFX"},
  {"marketSegmentId":"DDA","marketId":"ROFX"},
  ...
]}

Instrumentos (Securities)

Los instrumentos se identifican por su símbolo y marketId. Ejemplos:

SímboloDescripciónCFI Code
DLR/JUN26Futuro de dólar Junio 2026FXXXSX
SOJ.ROS/MAY26Futuro de soja Rosario Mayo 2026FXXXSX
DLR/JUN26 1460 COpción Call sobre futuro dólarOCAFXS
DLR/JUN26 1420 POpción Put sobre futuro dólarOPAFXS
GGALAcción Grupo GaliciaESXXXX

Todos los Instrumentos

GET https://api.remarkets.primary.com.ar/rest/instruments/all

Instrumentos con Detalle

GET https://api.remarkets.primary.com.ar/rest/instruments/details

Devuelve: symbol, segment, lowLimitPrice, highLimitPrice, minPriceIncrement, minTradeVol, maxTradeVol, tickSize, contractMultiplier, roundLot, maturityDate, currency, orderTypes, timesInForce, cficode.

Detalle de un Instrumento

GET https://api.remarkets.primary.com.ar/rest/instruments/detail?symbol=DLR/JUN26&marketId=ROFX

Por Código CFI

GET https://api.remarkets.primary.com.ar/rest/instruments/byCFICode?CFICode=FXXXSX
CFI CodeTipo
FXXXSXFuturo
FXXXXXFuturo (genérico)
OCAFXSOpción Call sobre Futuro
OPAFXSOpción Put sobre Futuro
OCEFXSOpción Call europea sobre Futuro
OPEFXSOpción Put europea sobre Futuro
ESXXXXAcción
DBXXXXBono
EMXXXXCEDEAR
OCASPSOpción Call sobre Acción
OPASPSOpción Put sobre Acción
DBXXFRObligación Negociable

Por Segmento

GET https://api.remarkets.primary.com.ar/rest/instruments/bySegment?MarketSegmentID=DDF&MarketID=ROFX

Market Data

En Tiempo Real (REST Snapshot)

GET https://api.remarkets.primary.com.ar/rest/marketdata/get
    ?marketId=ROFX
    &symbol=DLR/JUN26
    &entries=BI,OF,LA,OP,CL,SE,OI
    &depth=3
EntrySignificado
BIBids (ofertas de compra en el book)
OFOffers (ofertas de venta en el book)
LALast (último precio operado)
OPOpening Price (precio de apertura)
CLClosing Price (cierre rueda anterior)
SESettlement Price (precio de ajuste, solo futuros)
HIHigh Price (máximo de la rueda)
LOLow Price (mínimo de la rueda)
TVTrade Volume (volumen operado en contratos)
OIOpen Interest (interés abierto, solo futuros)
IVIndex Value (solo índices)
EVEffective Volume (solo BYMA)
NVNominal Volume (solo BYMA)
ACPAuction Price (cierre del día corriente)
r = requests.get("https://api.remarkets.primary.com.ar/rest/marketdata/get",
    headers={"X-Auth-Token": token},
    params={"marketId": "ROFX", "symbol": "DLR/JUN26",
            "entries": "BI,OF,LA,OP,CL,SE,OI", "depth": 3})
data = r.json()["marketData"]
print(f"Bid: {data['BI']}  |  Offer: {data['OF']}")
print(f"Last: {data['LA']}  |  Settle: {data['SE']}")

Histórica (Trades)

GET https://api.remarkets.primary.com.ar/rest/data/getTrades
    ?marketId=ROFX
    &symbol=DLR/JUN26
    &dateFrom=2026-06-01
    &dateTo=2026-06-08

Parámetros: marketId, symbol, date (una fecha), dateFrom/dateTo (rango), external (para mercados externos), environment (REMARKETS).

r = requests.get("https://api.remarkets.primary.com.ar/rest/data/getTrades",
    headers={"X-Auth-Token": token},
    params={"marketId": "ROFX", "symbol": "DLR/JUN26",
            "date": "2026-06-05"})
trades = r.json()["trades"]
for t in trades[:3]:
    print(f"{t['datetime']}  {t['price']}  {t['size']}")

Órdenes

Tipos de Órdenes

TipoDescripción
LIMITOrden con precio límite
MARKETOrden a mercado
STOP_LIMITOrden stop que se activa como limit
MARKET_TO_LIMITMarket que se convierte en limit

Nota: STOP_LIMIT y MARKET_TO_LIMIT no están disponibles para todos los instrumentos. Verificar orderTypes en el detalle del instrumento.

Time in Force (TIF)

TIFDescripción
DAYSolo válida por el día. Se expira al cierre de rueda
IOCImmediate or Cancel
FOKFill or Kill
GTDGood Till Date (requiere expireDate)

Ingresar Orden (REST)

GET https://api.remarkets.primary.com.ar/rest/order/newSingleOrder
    ?marketId=ROFX
    &symbol=DLR/JUN26
    &side=BUY
    &orderQty=10
    &ordType=LIMIT
    &price=1450.0
    &timeInForce=DAY
    &account=TU_CUENTA
    &cancelPrevious=False
    &iceberg=False

Parámetros:

ParámetroTipoObligatorioDescripción
marketIdStringROFX
symbolStringSímbolo del instrumento
sideStringBUY o SELL
orderQtyIntegerCantidad de contratos
ordTypeStringLIMIT o MARKET
priceFloatCondicionalRequerido para LIMIT
timeInForceStringNoDAY (default), IOC, FOK, GTD
accountInteger/StringNúmero de cuenta
cancelPreviousBooleanNoCancela órdenes previas del mismo contrato/lado
icebergBooleanNoOrden Iceberg (default: false)
displayQtyIntegerCondicionalCantidad a divulgar (para iceberg)
expireDateDateCondicionalRequerido para GTD (formato: YYYYMMDD)

Respuesta:

{"status":"OK","order":{"clientId":"21581341758","proprietary":"PBCP"}}

El clientId es el clOrdId (Client Order ID) que se usa para consultar/cancelar la orden.

Ingresar Orden (WebSocket)

{"type":"no","product":{"marketId":"ROFX","symbol":"DLR/JUN26"},
 "price":185,"quantity":23,"side":"BUY","account":"20","iceberg":false}

Para identificar la orden vía WebSocket, incluir wsClOrdId:

{"type":"no","product":{"marketId":"ROFX","symbol":"DLR/JUN26"},
 "price":185,"quantity":23,"side":"BUY","account":"20",
 "iceberg":false,"wsClOrdId":"mioid-unico-123"}

Respuesta WebSocket (Execution Report):

{"type":"or","orderReport":{"orderId":"1128056","clOrdId":"user14545...",
 "status":"PENDING_NEW","text":"Enviada","wsClOrdId":"mioid-unico-123"}}

Importante: El wsClOrdId solo aparece en el primer execution report. Luego se debe usar el clOrdId devuelto para seguimiento.

Reemplazar Orden

GET https://api.remarkets.primary.com.ar/rest/order/replaceById
    ?clOrdId=user144733478280357
    &proprietary=api
    &price=17
    &orderQty=10

Cancelar Orden

GET https://api.remarkets.primary.com.ar/rest/order/cancelById
    ?clOrdId=ajduj3l13ieci2jr4ck
    &proprietary=PBCP

Cancelar por WebSocket

{"type":"co","clientId":"user114121092035207","proprietary":"PBCP"}

Consultar Estado de la Orden (REST)

EndpointDescripción
GET /rest/order/id?clOrdId=...&proprietary=apiÚltimo estado del request
GET /rest/order/allById?clOrdId=...&proprietary=apiTodos los estados del request
GET /rest/order/byOrderId?orderId=...Estado por Order ID
GET /rest/order/actives?accountId=10Órdenes activas (NEW o PARTIALLY_FILLED)
GET /rest/order/filleds?accountId=10Órdenes total o parcialmente operadas
GET /rest/order/all?accountId=10Todos los estados de la cuenta
GET /rest/order/byExecId?execId=T1234567Estado por Execution ID

Execution Reports (WebSocket)

Suscribirse a una cuenta:

{"type":"os","account":{"id":"40"}}

Varias cuentas:

{"type":"os","accounts":[{"id":"40"},{"id":"4000"}]}

Todas las cuentas:

{"type":"os"}

Solo órdenes activas:

{"type":"os","snapshotOnlyActive":true}

Risk API

La Risk API usa HTTP Basic Auth con el mismo user/password, no token. Requiere el header Authorization: Basic <base64> adicionalmente al X-Auth-Token.

import base64
auth = base64.b64encode(f"{user}:{password}".encode()).decode()
headers = {"X-Auth-Token": token, "Authorization": f"Basic {auth}"}

Posiciones de una Cuenta

GET https://api.remarkets.primary.com.ar/rest/risk/position/getPositions/{accountName}
r = requests.get(f"https://api.remarkets.primary.com.ar/rest/risk/position/getPositions/TU_CUENTA",
    headers=headers)
positions = r.json()["positions"]
for p in positions:
    print(f"{p['symbol']}  Buy:{p['buySize']}  Sell:{p['sellSize']}  Diff:{p['totalDiff']}")

Posiciones Detalladas

GET https://api.remarkets.primary.com.ar/rest/risk/detailedPosition/{accountName}

Devuelve desglose por instrumento con: contractType, marketPrice, currency, exchangeRate, contractMultiplier, buyCurrentSize, sellCurrentSize, detailedDailyDiff.

Reporte de Cuenta

GET https://api.remarkets.primary.com.ar/rest/risk/accountReport/{accountName}
import base64
auth = base64.b64encode(f"{user}:{password}".encode()).decode()
headers = {"X-Auth-Token": token, "Authorization": f"Basic {auth}"}
r = requests.get(f"https://api.remarkets.primary.com.ar/rest/risk/accountReport/TU_CUENTA",
    headers=headers)
data = r.json()["accountData"]
print(f"Colateral: {data['collateral']}")
print(f"Margen: {data['margin']}")
print(f"Disponible: {data['availableToCollateral']}")
# Saldos por moneda
for moneda, saldo in data['detailedAccountReports']['0']['currencyBalance']['detailedCurrencyBalance'].items():
    print(f"  {moneda}: consumido={saldo['consumed']}  disponible={saldo['available']}")

WebSocket

URL: wss://api.remarkets.primary.com.ar/

La API WebSocket recibe mensajes asíncronos. El token se envía como header en la conexión:

import websocket

ws = websocket.WebSocketApp(
    "wss://api.remarkets.primary.com.ar/",
    header=[f"X-Auth-Token: {token}"],
    on_open=on_open,
    on_message=on_message,
    ...
)
ws.run_forever()

Los mensajes tienen el formato:

typeSignificado
noNew Order (enviar orden)
coCancel Order (cancelar orden)
orOrder Report (execution report recibido)
osOrder Subscription (suscribirse a reports)
smdSubscribe Market Data
MdMarket Data (recibido)

Market Data por WebSocket

{"type":"smd","level":1,"entries":["OF","BI","LA"],
 "products":[{"symbol":"DLR/JUN26","marketId":"ROFX"}],"depth":2}

Respuesta:

{"type":"Md","instrumentId":{"marketId":"ROFX","symbol":"DLR/JUN26"},
 "marketData":{"OF":[{"price":189,"size":21},{"price":188,"size":13}]}}

Estados de una Orden

EstadoSignificado
PENDING_NEWEnviada al mercado, aún no procesada
NEWAceptada, activa en el book
PARTIALLY_FILLEDParcialmente operada
FILLEDTotalmente operada
CANCELLEDCancelada
REJECTEDRechazada (ver text para motivo)
PENDING_CANCELCancelación en proceso
PENDING_REPLACEReemplazo en proceso
REPLACEDReemplazada
PENDING_APPROVALPendiente de aprobación

Errores Comunes

ErrorCausaSolución
401 UnauthorizedToken inválido o expiradoRenovar con /auth/getToken
"No tiene acceso a la cuenta"Account ID incorrectoVerificar accountId
"Product doesn't exist"Symbol incorrectoVerificar símbolo con instruments/all
"Access Denied"Sin permisos para el endpointVerificar segmento/método
"Ruta invalida"Endpoint no existeRevisar URL
Bid/Offer vacíosMercado cerrado o sin liquidezConsultar en horario de rueda

Scripts de Ejemplo

Ver ./scripts/:

# Autenticación y token (opcional, los scripts hacen login automático)
export PRIMARY_USER="tu_usuario"
export PRIMARY_PASSWORD="tu_password"
export PRIMARY_ACCOUNT="TU_CUENTA"

# Listar segmentos e instrumentos
python scripts/instruments.py --user $PRIMARY_USER --password $PRIMARY_PASSWORD

# Market data de un futuro
python scripts/market_data.py --user $PRIMARY_USER --password $PRIMARY_PASSWORD \
    --symbol DLR/JUN26 --entries BI,OF,LA

# Ver reporte de cuenta
python scripts/check_account.py --user $PRIMARY_USER --password $PRIMARY_PASSWORD \
    --account TU_CUENTA

# Ver posiciones
python scripts/check_positions.py --user $PRIMARY_USER --password $PRIMARY_PASSWORD \
    --account TU_CUENTA

# Enviar orden (¡cuidado! orden real en live)
python scripts/place_order.py --user $PRIMARY_USER --password $PRIMARY_PASSWORD \
    --symbol DLR/JUN26 --side BUY --qty 1 --type LIMIT --price 1450 --account TU_CUENTA

# WebSocket: Market Data en tiempo real
python scripts/websocket_md.py --user $PRIMARY_USER --password $PRIMARY_PASSWORD \
    --symbols DLR/JUN26 --entries BI,OF,LA --depth 3

# WebSocket: Execution Reports
python scripts/websocket_orders.py --user $PRIMARY_USER --password $PRIMARY_PASSWORD \
    --account TU_CUENTA

# WebSocket: Enviar orden (requiere suscripción a execution reports aparte)
python scripts/websocket_send_order.py --user $PRIMARY_USER --password $PRIMARY_PASSWORD \
    --symbol DLR/JUN26 --side BUY --qty 1 --type LIMIT --price 1450 --account TU_CUENTA

# WebSocket: Cancelar orden
python scripts/websocket_send_order.py --user $PRIMARY_USER --password $PRIMARY_PASSWORD \
    --cancel --clordid user12345... --proprietary PBCP

Glosario de Campos

CampoDescripción
clOrdIdClient Order ID — ID del request al mercado
orderIdOrder ID — ID de la orden en el mercado
execIdExecution ID — ID de una ejecución particular
proprietaryUsuario FIX que envió la orden (PBCP o ISV_PBCP)
wsClOrdIdID de orden enviada por WebSocket (solo en 1er report)
avgPxPrecio promedio operado
cumQtyCantidad acumulada operada
leavesQtyCantidad remanente
lastPxÚltimo precio operado
lastQtyÚltima cantidad operada
transactTimeFecha y hora de la transacción
tickSizeIncremento mínimo de cantidad
minPriceIncrementIncremento mínimo de precio (tick price)
contractMultiplierMultiplicador del contrato
maturityDateFecha de vencimiento
priceConvertionFactorFactor para precio unitario
lowLimitPriceLímite mínimo de precio
highLimitPriceLímite máximo de precio

Signals

GitHub stars
237
Forks
35
Last commit
Jun 2026
Advanced
Catalog kind
skill
Gateway key
primary
Source
github.com/gauss314/skills