PáginasDatos de calendario · 13 / 29
Módulo de calendario
El módulo de calendario da a tu estrategia el historial de dividendos, el historial de splits, las fechas de resultados, la fecha de salida a bolsa y las presentaciones recientes ante la SEC de una empresa, y permite que el backtest aplique automáticamente los splits y dividendos a tus posiciones.
Activa Include calendar data en la pestaña Symbol & data del cuadro Run backtest. Está activado por defecto, y tu elección (junto con las dos subopciones) se recuerda para la siguiente ejecución. Los calendarios se cargan automáticamente para cada símbolo que opera la ejecución, incluido un universo resuelto por un screener; no hay selector por ticker. El cuadro Test de un agente tiene la misma opción — Include calendar data (dividends, splits) (consulta Agentes).
Solo backtests. Los datos de calendario se cargan para backtests, Debug Test y pruebas de agentes. Las ejecuciones forward — chart forward tests, ejecuciones bulk de AutoTrading y QuantCloud — nunca reciben un calendario, así que calendar allí es siempre None.
Por qué importa: las barras de precio son crudas
Las velas del backtest no están ajustadas. Sin datos de calendario:
- Un split 4 por 1 parece un desplome del 75 % del precio de un día para otro, y tu posición simulada se desploma con él.
- Los dividendos nunca llegan, lo que subestima discretamente la rentabilidad total de cualquier posición mantenida mucho tiempo — aproximadamente un 2 %/año para un pagador de dividendos típico.
Las dos subopciones corrigen ambas cosas sin necesidad de cambiar código.
El parámetro de callback calendar
Añade un parámetro calendar a cualquier callback y se te pasa el manejador:
def on_bar(bar_index, bar, calendar=None, symbol=None):
if calendar is None: # always guard — not every run enables calendar data
return
days = calendar.days_to_earnings(bar["t"], symbol)
if days is not None and days <= 2:
return # sit out the earnings print
divs = calendar.dividends(bar["t"], symbol)
if divs and (divs[-1].amount or 0) > 0.5: # amount can be None
...Funciona en on_bar, on_tick y on_timer. El argumento calendar se asocia por nombre, así que un script sin parámetro calendar se comporta exactamente como antes, y un calendar declarado recibe el manejador o None — nunca otro objeto, sea lo que sea lo demás que tome tu firma. Si también lees datos fundamentales, la firma recomendada es def on_bar(bar_index, bar, fundamentals=None, calendar=None, symbol=None).
También puedes llegar al mismo manejador sin parámetro: la variable global del script qc_calendar, o quantcraft.process.runtime.qc_calendar.
Métodos
| Método | Devuelve |
|---|---|
dividends(bar_time, symbol=None) | Dividendos públicos en esa barra |
splits(bar_time, symbol=None) | Splits anunciados hasta esa barra |
filings(bar_time, symbol=None) | Presentaciones ante la SEC públicas en esa barra |
next_earnings(bar_time, symbol=None) | {date, basis, estimated, …} o None |
days_to_earnings(bar_time, symbol=None) | int o None |
ipo_date(symbol=None) | date o None |
current(bar_time, symbol=None) | Un diccionario instantáneo de todo lo anterior en esa barra, o None |
dividends_between(start, end, symbol=None) | Dividendos cuya fecha ex-dividendo cae en (start, end] |
splits_between(start, end, symbol=None) | Splits cuya fecha efectiva cae en (start, end] |
has(symbol=None) | Si este símbolo tiene datos de calendario |
symbols / primary_symbol() / get(symbol=None) | Los símbolos cargados, el predeterminado y el calendario en bruto por símbolo (o None) |
Los métodos _between usan las fechas de efecto («¿cuándo afecta a mi posición?»), a diferencia de los métodos por hora de barra anteriores, que usan las fechas de «¿podría haberlo sabido?» — consulta la siguiente sección.
bar_time acepta bar["t"], bar.t[0], un datetime, un date o segundos epoch.
Las listas van de la más antigua a la más reciente — dividends(...)[-1] es la más reciente. Es lo contrario de los datos fundamentales, donde el índice 0 es el periodo más reciente.
Un símbolo sin datos de calendario devuelve [] o None, nunca un error. La mayoría de los tickers fuera de las grandes capitalizaciones no tienen calendario en el servidor, así que comprueba si está vacío en lugar de esperar excepciones.
Dos fechas por evento: usa la correcta
Cada dividendo y cada split lleva dos fechas, y elegir la incorrecta introduce sesgo de anticipación:
| «¿Podría haberlo sabido?» | «¿Cuándo afecta a mi posición?» | |
|---|---|---|
| Dividendo | declaration_date | ex_date |
| Split | filing_date | effective_date |
dividends() / splits() / filings() filtran por la primera columna: devuelven solo lo que era público en tu barra. Un split suele ser visible semanas antes de que entre en vigor, porque el 8-K se presenta con antelación:
from datetime import date
bar_date = date.fromisoformat(str(bar["t"])[:10])
splits = calendar.splits(bar["t"], symbol)
upcoming = [s for s in splits
if s.effective_date and s.effective_date > bar_date] # announced, not yet effectiveCampos de los eventos
DividendEvent: ex_date, amount, estimated, type, declaration_date,
record_date, payment_date, period_end
SplitEvent: effective_date, ratio, type ("forward" | "reverse"), filing_date, form
FilingEvent: form, filing_date, report_date, items, category,
accession_number, primary_document, primary_document_description
IpoInfo: date, first_trade_date, sourceamount (dividendos) y effective_date (splits) pueden ser None: comprueba antes de comparar.
La category de una presentación es una de earnings, acquisition, officer-director, charter-amendment, agreement, regulation-fd, auditor-change, shareholder-vote, cybersecurity, other.
El indicador estimated
EDGAR no publica las fechas ex-dividendo. Salvo que hubiera datos del mercado disponibles, la fecha ex-dividendo se estima como la fecha de declaración + 10 días y es precisa a unos ±7 días, con estimated is True. Por defecto, la simulación sigue abonando los dividendos estimados (política best_available); un preajuste de ejecución (.qcs) puede establecer dividendDatePolicy en exact_only (omitir los estimados) u off — no hay control en el cuadro para esto. Filtra por él en tu propia lógica si tu estrategia es sensible a la fecha ex-dividendo:
exact = [d for d in calendar.dividends(bar["t"], symbol) if not d.estimated]Acciones corporativas en la simulación
Ambas subopciones están activadas por defecto cuando los datos de calendario lo están, y ambas se ejecutan antes de tus callbacks en cada barra, así que on_bar siempre ve una posición ya ajustada.
Ajustar las posiciones por splits de acciones — en la fecha efectiva, el número de acciones se multiplica por la proporción y el coste base se divide por ella. Los precios de stop y objetivo también se reescalan. Como qty × entry_price no cambia, tu curva de capital permanece continua a través del split.
Las barras de precio se mantienen deliberadamente sin ajustar, así que bar["close"] es el precio histórico real. Un indicador calculado sobre la serie de cierres en bruto seguirá viendo el salto del split: ajusta tu propia serie con calendar.splits(...) si eso importa.
Abonar los dividendos en efectivo — en la fecha ex-dividendo, qty × amount se suma al efectivo en las posiciones largas y se resta en las cortas (un vendedor en corto debe el dividendo al prestamista). Esto fluye al capital y a todas las métricas de rentabilidad, pero no a realized_pnl, que sigue siendo solo de operaciones. Lee los totales de las métricas de la cuenta:
def on_finish(bars, symbol=None, bars_by_symbol=None):
from quantcraft.process.runtime import account
m = account.refresh_metrics({})
print(m["total_dividend_income"], m["total_splits_applied"])Dónde ves las acciones corporativas
Nada cambia tu posición ni tu efectivo en silencio:
- Panel de salida — una línea
[calendar]por acción corporativa aplicada, más un resumen al final:[calendar] 2024-01-10 AAPL — SPLIT 4:1 applied to 1 position(s): 100 -> 400 shares (cost basis unchanged; bars stay unadjusted) [calendar] 2024-02-09 AAPL — DIVIDEND $0.2400/share on 400 share(s): +$96.00 cash … [calendar] corporate actions — 1 split(s) applied; 1 dividend(s) applied (0 exact ex-date, 1 estimated +/-7d) - Test Results — una fila Split o Dividend aparece intercalada entre las operaciones cerradas (la tarjeta se titula entonces Closed trades & events), mostrando la proporción o el importe por acción y el impacto en efectivo. Una fecha ex-dividendo estimada se marca como
est.Estas filas no llevan marcador#en el gráfico y se excluyen de la exportación CSV.
next_earnings es de un instante concreto
En un backtest, next_earnings nunca devuelve la «próxima fecha de resultados» del servidor calculada a fecha de hoy — eso sería sesgo de anticipación en una barra histórica. Se reconstruye a partir de la última presentación de resultados visible en tu barra más la cadencia de publicación de la empresa, así que basis == "filing-cadence" y estimated is True.
Devuelve None cuando aún no hay ninguna presentación de resultados visible — al principio de una ejecución, o para un símbolo cuyo historial de presentaciones no llega tan atrás. Compruébalo siempre.
Cuando no ves dividendos
Una ejecución que no aplica nada explica por qué en el panel de salida:
| El registro dice | Significado |
|---|---|
loaded 3/5 symbol(s); 2 without calendar data | Se imprime al inicio: cuántos símbolos obtuvieron un calendario |
none of 5 symbol(s) returned calendar data: … | Ningún símbolo de la ejecución tiene datos de calendario — no se puede aplicar nada |
no calendar data on the server | La tarea de calendario no se ha ejecutado para ese símbolo |
calendar has no dividend or split history | No paga dividendos, sin splits registrados |
… ex-dates 2019-05-10..2020-05-08 | Paga, pero no dentro de tu rango de fechas probado |
N with no ex-date, which can never be applied | Hay historial pero no se puede situar en el reloj |
no positions were held … | No había nada abierto cuando venció una acción |
Si no aparece ninguna línea [calendar], los datos de calendario no se adjuntaron a la ejecución: revisa el interruptor Include calendar data de la pestaña Symbol & data.
Véase también
- Backtests — el cuadro Run backtest y la opción Include calendar data
- Ciclo de vida de la estrategia — parámetro de callback
calendar, variable global de ejecuciónqc_calendar - Modelo de cuenta — dónde acaban el efectivo de dividendos y los ajustes por splits
- Screener — cómo se cargan los calendarios cuando un screener resuelve la lista de tickers
- Resultados de las pruebas — filas Split / Dividend en la tabla de operaciones cerradas
- Panel de salida — líneas de registro
[calendar]

