Guardado de la disposición
ChartStatePersistence reúne la disposición del gráfico —opciones, paneles, escalas de precio, series, indicadores y objetos gráficos— en una única instantánea JSON verificada y la restaura de vuelta. Los datos de las barras no entran en la instantánea: se guarda la configuración, y las cotizaciones llegan de su propia fuente.
La capa no posee ni el almacenamiento ni la regla de nomenclatura de las claves. Dónde escribir (archivo, backend, localStorage, IndexedDB) y cómo separar las instantáneas (por disposición, por instrumento, por usuario) lo decide la aplicación mediante una implementación de ChartStateStorage y la función key.
Creación y actualización
La importación se hace desde el punto de entrada @stocksharp/chart/persistence:
import { createChart, CandlestickSeries } from '@stocksharp/chart';
import { DrawingController } from '@stocksharp/chart/drawings';
import {
ChartStatePersistence,
NativeChartLayoutAdapter,
IndicatorEngineStateAdapter,
type ChartStateStorage,
type IndicatorEnginePersistenceApi,
} from '@stocksharp/chart/persistence';
declare const indicatorEngine: IndicatorEnginePersistenceApi;
const chart = createChart(document.querySelector<HTMLElement>('#chart')!, {});
chart.addSeries(CandlestickSeries, { id: 'price', upColor: '#26a69a', downColor: '#ef5350' });
const storage: ChartStateStorage = {
load: key => localStorage.getItem(key),
save: (key, value) => { localStorage.setItem(key, value); },
remove: key => { localStorage.removeItem(key); },
};
const persistence = new ChartStatePersistence<{ layoutId: string; symbol: string }>({
layout: new NativeChartLayoutAdapter({ chart, mainPaneId: 'main' }),
indicators: new IndicatorEngineStateAdapter({ engine: indicatorEngine }),
drawings: new DrawingController({ chart }),
storage,
key: ({ layoutId, symbol }) => `chart:${layoutId}:${symbol}`,
pretty: true,
});
const context = { layoutId: 'desk', symbol: 'BTC@IMEX' };
await persistence.save(context);
const restored = await persistence.load(context);
if (restored !== null) {
console.log(restored.state.panes.length);
console.log(restored.drawings.skipped); // los objetos de tipos desconocidos se omiten, no arruinan la restauración
}
El parámetro de tipo TContext es lo que se pasa a save, load y remove; la función key convierte el contexto en una cadena de clave y está obligada a devolver una cadena no vacía. pretty: true escribe el JSON con sangrado.
DrawingController debe ser la misma instancia que atiende el dibujo en el gráfico; de lo contrario se guardará un conjunto de objetos vacío.
Adaptadores
ChartStatePersistence no conoce ni la API nativa del gráfico ni el motor de indicadores: trabaja mediante dos adaptadores. Las implementaciones ya preparadas forman parte del mismo módulo, pero con una arquitectura propia se pueden pasar las suyas: las interfaces ChartStateLayoutAdapter (capture, restore) y ChartStateIndicatorAdapter (capture, clear, restore) son abiertas.
NativeChartLayoutAdapter captura y devuelve la disposición del propio gráfico: las opciones del gráfico, los paneles con su orden, altura, altura mínima y estado (normal, minimized, maximized), los ajustes de las escalas de precio y también las series con su tipo, panel, escala y opciones de estilo. Opciones del constructor:
chart: la instancia del gráfico (obligatoria).mainPaneId: identificador del panel raíz que sobrevive a la restauración; de forma predeterminadamainy, si no, el primer panel.createSeries(series, pane): creación propia de la serie en lugar del registro de tipos, cuando hay que conectar la serie a una fuente de datos.includeSeries(series): filtro; una serie para la que se devuelvefalseno se guarda ni se elimina durante la restauración.onRemoveSeries(series): se llama para una serie ajena que la restauración se ha visto obligada a desconectar porque su panel no forma parte de la disposición que se carga.onUnknownSeries(series): el tipo de serie no está en el registro.
Una serie con la opción persist: false queda excluida de la instantánea igual que una rechazada por el filtro includeSeries.
IndicatorEngineStateAdapter guarda la configuración de los indicadores —tipo, parámetros, estilos de dibujo, vínculo con el panel y la escala, visibilidad y origen—, pero no los valores calculados: tras la restauración se vuelven a calcular. Opciones del constructor:
engine: el motor de indicadores que implementaIndicatorEnginePersistenceApi(getIndicators,removeAll,add,setVisible).resolveTargetPaneId(indicator): correspondencia entre el panel guardado y el panel del anfitrión, cuando los identificadores difieren.onUnknownIndicator(indicator): el motor no ha podido crear un indicador de ese tipo.onUnknownStyle(indicator, styleId): en los estilos ha aparecido un identificador que el indicador no tiene.
Un indicador que se calcula sobre la salida de otro indicador se restaura después de este: el adaptador ordena por sí mismo la cadena de orígenes e informa de un error si la referencia lleva a un indicador ausente o si el grafo tiene ciclos.
Formato del estado y migraciones
La instantánea se describe con el tipo ChartStateV1, con los campos schemaVersion, chartOptions, panes, series, indicators, drawings; la versión actual del esquema es la constante CHART_STATE_SCHEMA_VERSION (igual a 1).
serializeChartState(state, { pretty }): comprueba el estado y lo convierte en una cadena JSON.deserializeChartState(value, { migrations }): analiza la cadena (o acepta un objeto ya preparado), ejecuta las migraciones hasta la versión actual y comprueba el resultado.normalizeChartStateV1(value): comprobación y congelación del estado; se rechazan las claves ajenas, los identificadores duplicados, las referencias a paneles inexistentes y una disposición sin ningún panel.normalizePersistedObject(value, path, { omitUndefined }): copia profunda de un JSON arbitrario en un objeto inmutable; se prohíben los ciclos, los valores no numéricos, un anidamiento excesivo y las claves__proto__,prototype,constructor.
Las instantáneas antiguas se elevan mediante migraciones paso a paso. El registro común chartStateMigrations ya contiene el paso de la versión 0 a la versión 1, y los pasos propios se registran así:
import {
ChartStateMigrationRegistry,
deserializeChartState,
} from '@stocksharp/chart/persistence';
const migrations = new ChartStateMigrationRegistry();
migrations.register(1, state => ({ ...state, schemaVersion: 2 }));
const state = deserializeChartState(json, { migrations });
Cada migración lleva el estado exactamente una versión hacia delante y está obligada a fijar el nuevo valor de schemaVersion. Una instantánea cuya versión sea superior a la admitida no se acepta para su carga.
Métodos públicos
snapshot(): reúne el estado actual del gráfico en unChartStateV1, sin acceder al almacenamiento.restore(state): aplica el estado al gráfico; devuelve{ state, drawings }, dondedrawingscontiene las listasrestoredyskipped.save(context): toma la instantánea, la serializa y la escribe en el almacenamiento con la clave calculada; devuelve el estado guardado.load(context): lee el registro por su clave, ejecuta las migraciones y lo restaura;nullsi el registro no existe.remove(context): elimina el registro del almacenamiento.
El orden de restauración es fijo: primero se liberan los indicadores, después se restaura la disposición de paneles y series, luego los indicadores y, en último lugar, los objetos gráficos.
El módulo exporta también los tipos que describen la instantánea y los adaptadores: ChartStateLayoutSnapshot, ChartStateRestoreResult, ChartStatePersistenceOptions, PersistedPane, PersistedPriceScale, PersistedSeries, PersistedIndicator, PersistedDrawing, PersistedChartOptions, PersistedSeriesOptions, PersistedIndicatorParameters, PersistedIndicatorStyles, PersistedObject, PersistedJsonValue, PersistableIndicatorEntry, RawChartState, ChartStateMigration, MaybePromise.