Ir al contenido

Crear una fuente de datos personalizada

Usa una fuente de datos personalizada para incorporar a AQE un mercado, un servicio de datos de mercado o tu propio conjunto de datos históricos. La fuente de datos no envía órdenes: puede funcionar con PaperBroker o con un adaptador de ejecución independiente.

Esta guía sigue las interfaces de AQE 0.2.0. Usa las definiciones de traits de la misma revisión de AQE que tu estrategia, especialmente al actualizar una integración existente.

Crea un tipo de Rust que sea propietario de tu cliente, el estado de conexión y las tareas de suscripción. Implementa aq_engine::core::broker::traits::{DataFeed, DataProvider} para ese tipo. Debe ser Send + Sync.

TraitMétodos requeridosResponsabilidad
DataFeedconnect, disconnect, is_connectedEstablecer y liberar el transporte; informar de su estado real.
DataProviderget_ticker_infoDevolver un Asset de AQE con el símbolo, las reglas de negociación y la precisión.
DataProviderget_historyDevolver un DataFrame de Polars para el símbolo, el intervalo de fechas UTC y el TimeFrame solicitados.
DataProviderget_latest_bar, get_latest_quoteDevolver una Bar o Quote, incluida su marca de tiempo de origen.
DataProvidersubscribe_to_data_stream, unsubscribe_from_data_streamGestionar callbacks de velas para los símbolos y el marco temporal solicitados.

Los traits usan métodos asíncronos nativos de Rust. connect y get_latest_quote requieren explícitamente futuros Send; una implementación con async fn puede cumplirlo cuando su estado capturado es Send. No mantengas una guarda de bloqueo que no sea Send a través de un .await.

Un intento de conexión cancelado debe dejar sus recursos bajo la propiedad del adaptador para que disconnect pueda liberarlos. Detén las tareas en segundo plano y libera las suscripciones al desconectar; evita trabajadores desvinculados que sigan entregando datos después.

Sobrescribe DataFeed::get_features() con un segmento estático de valores DataFeedFeature. El valor predeterminado es un segmento vacío.

  • Historial y precios actuales: HistoricalCandles, LatestCandle, LatestQuote.
  • Entrega de velas: CandleStream y, solo cuando esté implementado, IntraCandleStream.
  • Cotizaciones independientes: QuoteStream, junto con NativeBidAsk o SyntheticQuotes, según corresponda.

Los métodos obligatorios del trait deben implementarse aunque no se admita una capacidad. Devuelve un BrokerError claro para una operación no compatible, en lugar de inventar datos o indicar que se ha completado correctamente sin hacer nada. Un adaptador que solo proporcione historial puede ser útil para backtests sin declarar compatibilidad con streaming en vivo.

Devolver metadatos completos del instrumento

Sección titulada «Devolver metadatos completos del instrumento»

get_ticker_info devuelve un Asset, no solo un símbolo. Rellena la identidad del instrumento, el tipo de activo, el mercado, los permisos de negociación y estas reglas de ejecución a partir de los metadatos del proveedor:

CamposQué proporcionar
min_order_size, quantity_baseLa cantidad mínima y la precisión de la cantidad reconocidas por AQE. Mantén la coherencia con las reglas de cantidad del centro de negociación.
max_order_size, max_total_sizeLos límites por orden y los límites agregados por símbolo, respectivamente. Usa None cuando el proveedor no comunique un límite; no confundas ambos límites.
min_price_increment, price_base, contract_sizeEl incremento de precio, la precisión del precio y el multiplicador del contrato, cuando se conozcan. No supongas que todos los instrumentos usan acciones o un multiplicador de uno.
trading_calendarUn Option<String> con el JSON del calendario registrado por el productor, incluida su fuente. Mantén None si se desconoce el horario; no deduzcas que la negociación es continua porque falten metadatos.
feesAssetFees para comisiones y swap cuando se proporcionen. Los metadatos actuales de comisiones usan commission.entry y commission.exit, cada uno con valores para posiciones largas y cortas; el swap usa swap.long y swap.short.

AssetFees::default() proporciona una configuración de gastos vacía; no demuestra que el centro no cobre gastos. Los campos de gastos heredados entry y exit se mantienen como alternativas de compatibilidad. Un centro de ejecución independiente puede tener reglas y costes distintos de los del proveedor de datos: valida los metadatos con la cuenta de ejecución en lugar de suponer que los datos de mercado por sí solos autorizan una orden.

Convierte los registros del proveedor en valores Bar de AQE, con marcas de tiempo UTC y símbolos coherentes. Gestiona explícitamente la paginación, el orden cronológico, los duplicados y los marcos temporales solicitados. No devuelvas silenciosamente un marco temporal diferente ni sustituyas el historial ausente por precios actuales.

Las tablas de datos históricos necesitan estas columnas:

ColumnaRepresentación canónica
symbolCadena de texto
open, high, low, close, volumef64
timestampMilisegundos Unix UTC como i64, tal como los produce el conversor predeterminado de AQE

Usa preferentemente el conversor existente en lugar de construir una tabla de datos manualmente. Esta función auxiliar presupone que ya has decodificado y validado la respuesta del proveedor como Vec<Bar>:

use aq_engine::core::broker::{
traits::DataProvider,
types::{Bar, BarData, BrokerError},
};
use polars::prelude::DataFrame;
pub fn normalise_history<D: DataProvider>(
provider: &D,
bars: Vec<Bar>,
) -> Result<DataFrame, BrokerError> {
provider
.format_on_bar(BarData::Bars(bars))
.map_err(BrokerError::DataFeedError)
}

Usa una versión de Polars compatible con tu dependencia de AQE. format_on_bar(BarData::Frame(...)) comprueba los nombres de las columnas requeridas; no valida por completo los tipos, el orden ni la calidad de los datos de mercado.

Una Quote nativa incluye symbol, bid, ask, tamaños, valores opcionales de la última operación y una marca de tiempo UTC. Usa precios finitos y positivos, ask >= bid y tamaños no negativos. Para una fuente basada solo en velas, Quote::from_bar_close(&bar) crea una cotización sintética bid=ask sin inventar el tamaño del libro de órdenes. Declara SyntheticQuotes, no NativeBidAsk, para esa representación.

Incluir el nuevo campo de valoración de cotizaciones

Sección titulada «Incluir el nuevo campo de valoración de cotizaciones»

Quote ahora también contiene profit_model. Añade este campo a los literales de estructura existentes de Rust, aunque tu proveedor no pueda proporcionar un modelo de valoración. Su atributo #[serde(default)] permite seguir leyendo cotizaciones serializadas antiguas; no rellena un campo ausente en el código fuente de Rust.

Para una fuente de datos genérica, usa profit_model: None. Este ejemplo presupone que los precios y la marca de tiempo recibidos ya se han validado; los tamaños cero indican que no se ha comunicado ningún tamaño, no que se haya inventado liquidez:

use aq_engine::core::broker::types::Quote;
use chrono::{DateTime, Utc};
pub fn quote_without_valuation(
symbol: String,
bid: f64,
ask: f64,
timestamp: DateTime<Utc>,
) -> Quote {
Quote {
profit_model: None,
symbol,
bid,
ask,
bid_size: 0.0,
ask_size: 0.0,
last: None,
last_size: None,
timestamp,
}
}

Adjunta un modelo BrokerQuoteProfit solo cuando el bróker de ejecución pueda proporcionar coeficientes válidos en la moneda de la cuenta para esa cuenta, símbolo y cotización. El modelo registra version, account_id, currency, symbol, as_of_us y coeficientes independientes buy_gain, buy_loss, sell_gain y sell_loss. La versión actual es 1; los coeficientes deben ser finitos y positivos. El momento de observación se expresa en microsegundos Unix UTC, mientras que el campo Quote.timestamp es un DateTime UTC.

Estos coeficientes son valores monetarios calibrados por el bróker por unidad de precio y unidad de cantidad del bróker, no una conversión genérica de divisas ni un registro de beneficios realizados. Conserva su cuenta, moneda, símbolo y vigencia; no los copies entre cuentas ni los inventes a partir del cierre de una vela. Quote::from_bar_close deja deliberadamente el modelo ausente. Estos metadatos no sustituyen los indicadores de capacidades de cotización existentes.

subscribe_to_data_stream recibe símbolos, un TimeFrame, un DataStreamMode y un callback Arc<dyn Fn(Bar) + Send + Sync>. Respeta el modo: CompletedBar entrega velas completadas; Intrabar permite actualizar la vela en formación. Mantén la ejecución de los callbacks breve y no bloqueante.

Para un proveedor basado en sondeo, inspecciona el DataStreamManager existente y el adaptador de Yahoo antes de escribir otro planificador. Un proveedor websocket puede gestionar sus propias tareas de lectura, pero debe respetar el mismo contrato de callbacks y cancelación de suscripciones.

El streaming de cotizaciones es opcional. Para declarar QuoteStream, sobrescribe tanto subscribe_to_quote_stream como unsubscribe_from_quote_stream. Cada suscripción tiene su propio ID: eliminarla no debe detener las cotizaciones ni las velas de otro consumidor. El método de suscripción predeterminado devuelve un error de operación no compatible. La API de cotizaciones no garantiza la entrega de todos los ticks del mercado.

Una vez que tu tipo implemente ambos traits, pasa una instancia a UnifiedBroker. Esta función auxiliar reutilizable acepta cualquier proveedor compatible; no implementa la API de red del proveedor:

use aq_engine::core::broker::{
paper_broker::PaperBroker,
traits::{DataFeed, DataProvider},
types::AccountType,
UnifiedBroker,
};
pub fn backtest_with<D>(datafeed: D) -> UnifiedBroker<PaperBroker, D>
where
D: DataFeed + DataProvider,
{
let execution = PaperBroker::new(AccountType::Paper, 100_000.0, 1);
UnifiedBroker::new_backtest(execution, datafeed)
}

Para operaciones en vivo o simuladas con datos en vivo, usa UnifiedBroker::new(execution, datafeed). Mantén la reproducción histórica en new_backtest; sus cotizaciones de reproducción proceden de velas consumidas, no de un endpoint de precios actuales del mercado.

Implementar estos traits permite usarlos en estrategias de Rust. Añadir un formulario de conexión o una opción de proveedor en AQS requiere una integración de escritorio independiente.

supports_historical_stream(symbol, timeframe) devuelve Ok(true) por defecto. Sobrescríbelo para conjuntos de datos finitos, de modo que se pueda omitir deliberadamente una combinación de símbolo y marco temporal no disponible. Mantén como errores los fallos reales de red, autenticación y datos; no uses este hook para ocultar una solicitud fallida ni sustituir silenciosamente un marco temporal por otro.

configure_live_session es un hook opcional de contexto de sesión cuya implementación predeterminada no realiza ninguna acción. No hace obligatorios los metadatos de valoración ni la conectividad con la nube para una fuente de datos personalizada.

  1. Prueba símbolos no válidos, historial vacío, paginación, conversión de marcas de tiempo y marcos temporales no compatibles.
  2. Verifica los valores OHLCV y el orden cronológico con un pequeño conjunto de datos conocido.
  3. Prueba por separado la entrega de velas completadas y las actualizaciones intravela, incluidas las reconexiones y los mensajes duplicados.
  4. Crea dos suscripciones de cotizaciones, elimina una y confirma que la otra siga activa.
  5. Desconecta durante la conexión y el streaming; verifica que se liberen todos los recursos propios.
  6. Ejecuta un backtest determinista de PaperBroker antes de conectar una cuenta de ejecución en vivo.
  7. Revisa todos los literales de estructura de Asset y Quote después de actualizar AQE. Prueba la ausencia de metadatos de valoración, los modelos desactualizados o de otras cuentas y las cotizaciones sintéticas sin tratar los valores no disponibles como un beneficio de cero.

En tu copia de trabajo de AQE, empieza por:

  • src/core/broker/mod.rs: DataFeed, DataProvider, DataStreamMode y UnifiedBroker.
  • src/core/broker/types/mod.rs: Asset, Bar, Quote, BarData y BAR_DATAFRAME_COLUMNS.
  • src/core/broker/features.rs: indicadores de capacidades compatibles.
  • src/core/broker/data_feeds/yahoo.rs: obtención de históricos, normalización y sondeo.
  • src/core/broker/data_stream.rs: gestión compartida de suscripciones de velas.
  • live-sync-protocol/src/quote_profit.rs: ámbito de aplicación de BrokerQuoteProfit, coeficientes y comprobaciones de vigencia.

Siguiente: Crear un bróker personalizado o Brókeres y fuentes de datos.