10. Datos de proceso (proc.*) y backtesting dinámico (especificación de diseño)
Este capítulo explica la definición y los métodos de acceso de datos de proceso en qteasy, así como la selección de ramas estáticas frente a ramas dinámicas durante las pruebas retrospectivas y las convenciones de coherencia entre ellas, como referencia al implementar y ampliar. Para obtener explicaciones a nivel de uso, léalo junto con «Cómo las estrategias declaran y utilizan datos» y la documentación de la API.
10.1. 1. 背景与目标
1.1 Significado de los datos del proceso
Algunas estrategias deben depender de datos que cambian con la ruta de ejecución de operaciones en vivo o de prueba retrospectiva, por ejemplo:
Posiciones actuales/históricas, efectivo disponible;
Cantidad histórica surtida, precio de ejecución, costos de transacción;
Valor de mercado, activos totales, etc. derivados de posiciones y precios.
Estos datos no se pueden generar previamente de una sola vez antes de que comience una prueba retrospectiva; solo puede mantenerse durante el tiempo de ejecución mediante Backtester (backtesting) o Trader (comercio en vivo) y proporcionarse a la estrategia en cada paso de la generación de señales de acuerdo con el «alcance actualmente visible». Nos referimos colectivamente a ellos como datos de proceso.
1.2 Objetivos de diseño
Punto de entrada unificado: al igual que los datos históricos estáticos, los datos del proceso se obtienen a través de
Strategy.get_data(), lo que reduce la curva de aprendizaje.Sin anticipación: al generar la señal para el paso k, la estrategia no puede ver los resultados de la ejecución del paso k; sólo puede utilizar el historial de pasos completados.
Consistencia en backtest/en vivo: el mismo conjunto de estrategias y el mismo patrón de llamadas
get_data('proc.xxx')se pueden usar tanto en backtesting como en operaciones en vivo; cuando se necesitan datos de proceso, sigue la ruta de ejecución dinámica; de lo contrario, puede permanecer coherente con la ruta estática original en términos de resultados.
10.2. 2. 过程数据的统一定义(proc.*)
2.1 Método de denominación y exposición
Todos los datos del proceso están expuestos a la estrategia en el formato
proc.<field_name>, comoproc.own_cashyproc.trade_records.Los datos del proceso no necesitan declararse mediante
data_typesen el__init__de la estrategia. Backtester / Trader lo inyecta en tiempo de ejecución, y la estrategia solo necesita llamar aget_data('proc.xxx', ...)enrealize()según sea necesario.
2.2 Campos integrados implementados
Los campos de datos de proceso implementados en la versión actual y disponibles para su uso en estrategias incluyen:
Categoría |
Nombre del campo |
Significado |
|---|---|---|
escalar de cuenta |
|
Efectivo total en la cuenta al inicio del paso actual |
|
Efectivo disponible para realizar pedidos al inicio del paso actual |
|
|
Valor total de mercado del activo al inicio del paso actual (valoración de la posición + efectivo) |
|
Vector de posición |
|
Cantidad de posición total de cada instrumento al inicio del paso actual |
|
Cantidad vendible para cada instrumento al inicio del paso actual |
|
|
Valor de mercado de posición para cada instrumento al inicio del paso actual (calculado a partir del precio interno y las posiciones) |
|
Resultados de ejecución |
|
Cantidad real ejecutada para cada instrumento en cada paso (positiva para compras, negativa para ventas) |
|
Costos de transacción para cada instrumento en cada paso. |
|
|
Precio de ejecución de cada instrumento en cada paso. |
Para conocer la semántica de tiempo y las limitaciones de visibilidad de los campos anteriores en backtesting y trading real, consulte la Sección 4.
2.3 Campos extensibles futuros (opcional)
Los campos que se pueden ampliar aún más por diseño incluyen: proc.realized_pnl, proc.unrealized_pnl, proc.last_trade_price, proc.last_trade_volume, etc. Consulte la implementación y la documentación para obtener más detalles.
10.3. 3. 访问接口:Strategy.get_data() 与 proc.*
3.1 Datos estáticos (sin prefijo de proceso)
Fuente única:
self.get_data('close_E_d'); múltiples fuentes:self.get_data('close_E_d', 'high_E_d').Los datos estáticos no admiten los parámetros
lag/window; si se proporciona, se genera unValueErroren inglés.
3.2 Datos de proceso (prefijo de proceso)
Ejemplos de llamadas:
self.get_data('proc.own_cash'): la serie de efectivo hasta el paso actual;self.get_data('proc.own_cash', lag=0): el valor en efectivo en el paso más reciente;self.get_data('proc.own_cash', lag='1d'): el paso correspondiente a mirar hacia atrás 1 día en el tiempo;self.get_data('proc.own_cash', window='5d'): un segmento de ventana durante los últimos 5 días.
Restricciones:
Una sola llamada permite sólo un campo
proc.*; si se utilizan varios campos o se mezcla con datos estáticos en una misma llamada, levantar unValueErroren inglés.lagywindowno se pueden especificar al mismo tiempo;lagpuede ser un número entero (pasos) o una cadena (por ejemplo,'1d','8h') ywindowes una cadena (por ejemplo,'5d','8h').
Valor de retorno: siempre
np.ndarray; la forma y el tipo de datos están sujetos a la documentación de la API.
10.4. 4. 回测分支选择与过程数据协作
4.1 Rama estática y rama dinámica
Rama estática (
_backtest_static_operator): llame arun_strategiesuna vez por todas para generar todas las señales, luego complete la prueba retrospectiva utilizando funciones vectorizadas de Numba comobacktest_batch_steps. Adecuado para estrategias que no dependen de datos de proceso.Rama dinámica (
_backtest_dynamic_operator): bucle en pasos de tiempo; en cada paso genere señales → analice y simule rellenos → actualice posiciones y efectivo, luego pase al siguiente paso. Los datos del proceso son mantenidos por Backtester y se inyectan en Operator antes de cada paso, por lo que las estrategias pueden acceder a ellos a través deget_data('proc.xxx').
Antes de ejecutarse, Backtester decide qué rama tomar a través de Operator.check_dynamic_data().
4.2 Lógica de decisión de check_dynamic_data() (implementación actual)
Si alguna de las siguientes condiciones es verdadera, devuelve True y toma la rama dinámica:
op_type == “stepwise”: Operator está configurado explícitamente en modo paso a paso.
Usando proc. en el código fuente de la estrategia*:
_strategies_use_proc_data()verifica si el código fuente derealize()de cada estrategia contiene'proc.'o"proc.". Si es así, se considera que depende de los datos del proceso.
Por lo tanto, siempre que se llame a get_data('proc.xxx') en realizar(), automáticamente tomará la rama dinámica sin ninguna declaración. Solo se accede a los datos del proceso a través de proc.*; ya no se admite declararlo a través de DataType (se han eliminado los tipos op_* heredados).
4.3 Sin garantía anticipada
Cuando la estrategia genera una señal en el paso k:
Los datos de cuenta/posición (por ejemplo,
own_cashes,own_amounts) son visibles como máximo hasta el índice[0..k](es decir, el estado al inicio del paso actual);Los datos relacionados con el comercio (por ejemplo,
trade_records,trade_cost) son visibles como máximo hasta[0..k-1], excluyendo los intercambios que aún no se han producido en este paso.
En la implementación, el
_current_signal_indexde Operator y el_get_process_data_single()de la estrategia se dividen según los rangos anteriores. El Backtester actualiza el índice antes de generar señales en cada paso, lo que garantiza que no haya anticipación.
4.4 La relación de inyección entre Backtester y Operator
Backtester (rama dinámica): en el punto de entrada
_backtest_dynamic_operator, inyecteown_cashes,available_cashes,own_amounts_array,available_amounts_array,trade_records_array,trade_cost_array,trade_price_array,trade_price_data, etc. en Operator como_process_data_sources, y establezca_process_time_indexen una línea de tiempo alineada conop_signal_index.Operator: En
run_strategy(step_index), antes de cada llamada astg.generate(), calcule y actualice_current_signal_indexsegúngroup_timing_tableygroup_merge_type, para que la estrategia divida los datos del proceso «actualmente visibles».
4.5 Procesar datos en operaciones reales (Trader)
Cuando operator.check_dynamic_data() es Verdadero, Trader, en _run_strategy(), hará lo siguiente:
Reúna el efectivo de la cuenta corriente, las posiciones, las cantidades disponibles, los precios actuales, etc. en un solo paso
_process_data_sourcesy_process_time_index(una sola ejecución de operaciones en vivo se trata como un solo paso);Dentro de este paso, la estrategia puede llamar a
get_data('proc.own_cash'), etc. para obtener la vista de cuenta/posición actual; el historial comercial está vacío dentro de este paso, lo que es consistente con la semántica de «aún no se han producido transacciones en este paso».
10.5. 5. 动态/静态路径一致性约定
Cuando una estrategia no utiliza datos de proceso: debe tomar la rama estática; Si toma la rama dinámica por otros motivos, los resultados del backtest deben ser exactamente idénticos numéricamente a los de la rama estática (bajo la misma configuración y datos).
Cuando una estrategia usa datos de proceso: debe pasar por la rama dinámica; de lo contrario, si no se inyecta
_process_data_sources, se generará un RuntimeError.Convención de prueba: use
StaticSignalStg(puramente estático) yProcAwareButStaticLogicStg(llama a proc pero no lo usa para señales) para realizar una prueba retrospectiva bajo la misma configuración y afirmar la coherencia numérica paraown_cashes,own_amounts_array,trade_records_array, etc.; consulte el Grupo B en ⟦CÓDIGO5⟧.
10.6. 6. 测试与文档索引
Pruebas dedicadas:
tests/test_process_data_api.pyGrupo A: el comportamiento de
check_dynamic_data()bajo estrategias/estrategias puramente estáticas usando proc.*;Grupo B: coherencia de la matriz de prueba retrospectiva entre estrategias estáticas y estrategias de «llamar a proc pero lógicamente equivalentes»;
Grupo C:
get_datacomportamiento de error para múltiples fuentes estáticas, rechazo de retraso/ventana, proc de campo único y llamadas mixtas;Grupo D: sin validación anticipada para
proc.trade_records;Grupo E: corrección de la ruta real de la estrategia dinámica basada en los datos del proceso.
Memoria del proyecto:
.cursor/rules/process-data-and-dynamic-backtest.mdc(resumen de implementación y convención).Resumen de los datos de la estrategia: Cómo las estrategias declaran y utilizan los datos; Modos y puntos de entrada de backtest: Backtesting, operaciones en vivo y optimización.