En fintech, moitas veces temos que procesar volumes bastante masivos de datos de tipos de cambio de moeda. Recibimos datos de diferentes fontes, e cada unha delas ten a súa propia idea de como extrapolar os tipos de cambio para mañá, pasadomañá, o próximo mes e mesmo os próximos tres anos. Se alguén puidese predecir as taxas correctamente, sería hora de pechar o negocio e simplemente cambiar o diñeiro de un lado a outro. Algunhas fontes son máis fiables, algunhas proporcionan lixo completo, con inclusións raras de valores case correctos, pero para parellas exóticas. O noso traballo é examinar estas decenas de miles de valores por segundo e determinar o que mostrar exactamente aos clientes. Necesitamos filtrar o valor correcto de toneladas de sucidade e limo, como fan os flamencos no xantar.

Un trazo distintivo especial dos flamencos é o seu enorme peteiro curvado cara abaixo, co que filtran os alimentos da auga ou do barro.
-
Así naceu a biblioteca , que almacena unha caché de estado para varios valores a intervalos de tempo especificados. Baixo o capó, filtra os datos malos e obsoletos sobre a marcha e tamén proporciona acceso ás últimas N valores validados para cada clave (pares de moedas, no noso caso).
Digamos que recollemos taxas de tres pares de divisas. Definición máis sinxela Vela para almacenar o estado actual terá un aspecto así:
defmodule Pairs do
use Vela,
eurusd: [sorter: &Kernel.<=/2],
eurgbp: [limit: 3, errors: 1],
eurcad: [validator: Pairs]
@behaviour Vela.Validator
@impl Vela.Validator
def valid?(:eurcad, rate), do: rate > 0
endActualización de valores
A función fará o seguinte en secuencia:
- provocará
validatorsobre o valor, se se define un (ver capítulo Validación abaixo); - engadirá o valor á fila de bos valores se a validación foi exitosa ou á fila de servizo
:__errors__en caso contrario; - provocará a clasificación se
sorterdefinido para unha chave determinada, ou simplemente poñerá o valor na cabeceira da lista (LIFO, ver capítulo Ordenación abaixo); - recortará a fila segundo o parámetro
:limitpasado sobre a creación; - devolverá a estrutura actualizada
Vela.
iex|1 > pairs = %Pairs{}
iex|2 > Vela.put(pairs, :eurcad, 1.0)
#⇒ %Pairs{..., eurcad: [1.0], ...}
iex|3 > Vela.put(pairs, :eurcad, -1.0)
#⇒ %Pairs{__errors__: [eurcad: -1.0], ...}
iex|4 > pairs |> Vela.put(:eurusd, 2.0) |> Vela.put(:eurusd, 1.0)
#⇒ %Pairs{... eurusd: [1.0, 2.0]}Tamén Vela apeiros , polo que podes usar calquera das funcións estándar para a actualización profunda das estruturas do arsenal para actualizar os valores : , , , e .
Validación
Un validador pódese definir como:
- función externa cun argumento (
&MyMod.my_fun/1), só recibirá o valor para validación; - función externa con dous argumentos,
&MyMod.my_fun/2, ela conseguirá un parserie, valuepara validación; - implementación de módulos ;
- parámetro de configuración
thresholde - opcionalmente -compare_by, ver capítulo comparación a continuación.
Se a validación ten éxito, o valor engádese á lista baixo a chave correspondente; se non, a tupla {serie, value} vai a :__errors_.
Comparación
Os valores almacenados nestas filas poden ser calquera cousa. Ensinar Vela para comparalos, é necesario transferir compare_by parámetro na definición da serie (a non ser que os valores non se poidan comparar co estándar Kernel.</2); este parámetro debe ser de tipo (Vela.value() -> number()). Por defecto é sinxelo & &1.
Ademais, pode pasar un parámetro á definición da fila comparator para calcular valores delta (min/max); por exemplo, transmitindo Date.diff/2 como comparador, podes obter os deltas correctos para as datas.
Outra forma conveniente de traballar é pasar un parámetro threshold, que define a relación máxima permitida do novo valor a {min, max} intervalo. Dado que se especifica como unha porcentaxe, o cheque non se utiliza comparatorpero aínda usa compare_by. Por exemplo, para especificar un valor límite para datas e horas, debes especificalo compare_by: &DateTime.to_unix/1 (para obter un valor enteiro) e threshold: 1, o que fai que só se permitan novos valores se están en ±band intervalo dos valores actuais.
Finalmente, podes usar Vela.equal?/2 para comparar dous cachés. Se os valores definen unha función equal?/2 ou compare/2, entón estas funcións serán usadas para a comparación, se non, usamos estúpidamente ==/2.
Obtención de valores
O procesamento do estado actual comeza normalmente coa chamada Vela.purge/1, que elimina os valores obsoletos (se validator atado a timestamps). Despois podes chamar Vela.slice/1que volverá keyword cos nomes das filas como claves e os primeiros valores reais.
Tamén podes usar get_in/2/pop_in/2 para acceso de baixo nivel aos valores de cada fila.
App
Vela pode ser moi útil como caché de series temporais nun estado de proceso como GenServer/Agent. Queremos nunca usar valores obsoletos do curso, e para iso simplemente mantemos o proceso co estado procesado Vela, co validador que se mostra a continuación.
@impl Vela.Validator
def valid?(_key, %Rate{} = rate),
do: Rate.age(rate) < @death_ageи Vela.purge/1 elimina silenciosamente todos os valores obsoletos cada vez que necesitamos os datos. Para acceder aos valores reais simplemente chamamos Vela.slice/1, e cando se require un pequeno historial do curso (toda a serie), simplemente o devolvemos -xa ordenado- cos valores validados.
Feliz almacenamento en caché de series temporais!
Fonte: www.habr.com
