Я пытаюсь использовать Rx, потому что он кажется подходящим для нашего домена, но кривая обучения застала меня врасплох.
Мне нужно связать исторические данные о ценах с данными о реальной стоимости.
Я пытаюсь адаптировать обычный подход к этому в язык Rx:
- Немедленно подпишитесь на прямые цены и начните буферизацию значений, которые я получаю.
- Инициировать запрос исторических данных о ценах (это должно произойти после подписки на живые цены, чтобы у нас не было пробелов в наших данных).
- Опубликовать исторические цены по мере их возвращения.
- Как только мы получим все исторические данные, опубликуем текущие данные с буферизацией, удалив любые значения, которые сначала совпадают с нашими историческими данными.
- Продолжить воспроизведение данных из текущего курса цены.
У меня есть этот отвратительный и неправильный код соломенного человека, который, похоже, работает для наивных тестов, которые я написал:
IConnectableObservable<Tick> live = liveService
.For(symbol)
.Replay(/* Some appropriate buffer size */);
live.Connect();
IObservable<Tick> historical = historyService.For(since, symbol);
return new[] {historical, live}
.Concat()
.Where(TicksAreInChronologicalOrder());
private static Func1<Tick,bool> TicksAreInChronologicalOrder()
{
// Some stateful predicate comparing the timestamp of this tick
// to the timestamp of the last tick we saw
}
У этого есть несколько недостатков
- Соответствующий размер буфера воспроизведения неизвестен. Установка неограниченного буфера невозможна - это длительная последовательность. На самом деле нам нужен какой-то одноразовый буфер, который срабатывает при первом вызове Subscribe. Если это существует в Rx, я не могу его найти.
- Буфер повтора будет продолжать существовать даже после того, как мы перейдем к опубликованию прямых цен. На данный момент буфер не нужен.
- Аналогично, предикат для отфильтровывания перекрывающихся тиков не нужен, как только мы пропустили начальное совпадение между историческими и живыми ценами. Я действительно хочу сделать что-то вроде:
live.SkipWhile(tick => tick.Timestamp < /* lazily get last timestamp in historical data */)
. Полезно ли здесьWait(this IObservable<TSource>)
?
Должен быть лучший способ сделать это, но я все еще жду, пока мой мозг не задержит Rx, как это делает FP.
Еще один вариант, который я решил решить 1. пишет собственное расширение Rx, которое будет ISubject
, которое ставит в очередь сообщения, пока не получит своего первого абонента (и после этого откажется от подписчиков?). Может быть, это путь?