我是Rx的新手,我试图制作一个GUI来显示股市数据。这个概念有点像ReactiveTrader,但是我需要显示整个"深度",即所有价格及其在市场上的买/卖数量,而不仅仅是& #34;顶级"市场买入/卖出,按价格排序。
每个"价格水平的数据结构"是这样的:
public class MarketDepthLevel
{
public int MarketBidQuantity { get; set; }
public decimal Price { get; set; }
public int MarketAskQuantity { get; set; }
}
在GUI下面,套接字侦听网络更新并将其作为Observable返回:
IObservable<MarketDepthLevel> MarketPriceLevelStream;
在转换为ReactiveList之后,最终绑定到DataGrid。
转型基本上会选择每个价格水平的最新更新,并按价格对其进行排序。所以我想出了类似的东西:
public IReactiveDerivedList<MarketDepthLevel> MarketDepthStream
{
get
{
return MarketDepthLevelStream
.Distinct(x => x.Price)
.CreateCollection()
.CreateDerivedCollection(x => x, orderer: (x, y) => y.Price.CompareTo(x.Price));
}
}
但有问题:
当&#39; Distinct&#39;看到与以前相同的价格,丢弃新的,但我需要新的替换旧的(因为它们包含持续的MarketBidQuantity / MarketAskQuantity)< / p>
CreateCollection / CreateDerivedColleciton似乎有点笨拙
有关解决这些问题的任何想法(尤其是第一个问题)? 感谢
答案 0 :(得分:0)
只需将项目分组,然后将每个组投影为该组中的最后一项:
return MarketDepthLevelStream
.GroupBy(x => x.Price, (key, items) => items.Last());
答案 1 :(得分:0)
如果我理解正确,您希望在每个级别的最新出价/要价数量列表中投放MarketDepthLevel
更新流(在财务术语中,这是一种阶梯< / em>的)。梯子保持为ReactiveList
绑定UI。 (ObserveOn
可能是必需的,虽然ReactiveList
在大多数情况下会处理这种情况,我相信)
这是一个从http://ratesetter.com快照的示例梯形图,其中“价格”表示为百分比(Rate),以及出价/要价大小按贷方所需金额和借款人在每个价格水平所需的数量:
此时,我开始有点迷失。我很困惑为什么你需要任何进一步的Rx操作符,因为你可以简单地Subscribe
更新流,并让处理程序更新数据绑定到UI的固定列表。如果新事件是新价格,或者用匹配价格替换现有条目,是否只需要将每个新事件添加到ReactiveList
?如果它是UI链中的最后一步,那么执行此操作的命令代码就可以了。
如果您需要将MarketDepthLevelStream
转换为梯形流,那么在Rx流本身中执行此操作只有价值。这可能很有用,但你没有提到这种需要。
这种需求可能是由于希望将流组播到许多订户,和/或因为您需要在梯子上进行进一步的转换或投影。
请记住,如果梯子很大,那么在UI中使用整个梯形图更新可能会给您带来性能问题 - 在许多情况下,单个更新到像ReactiveList
这样的可变结构是一种实用的方法去。
如果使用梯子 是一项要求,请查看Observable.Scan
。这是Rx的工作马操作员,维护当地的州。它用于任何形式的运行聚合 - 例如运行总计,平均值等,或者在这种情况下是梯形图。
现在,如果您需要的只是上面描述的静态列表,我可能会在这里大肆绕道,但这是一次有用的讨论......
您需要仔细考虑用于梯形聚合的类型 - 您需要了解如何使用下游事件。它可能需要一个 immutable 集合类型,以便订阅者不会感到奇怪(每个事件实际上应该是梯形图的静态快照)。使用immutable collections,考虑内存效率可能很重要。
这是一个简单的示例,说明梯形流如何工作,使用来自nuget预发布包System.Collections.Immutable
的不可变集合:
public static class ObservableExtensions
{
public static IObservable<ImmutableSortedDictionary<decimal, MarketDepthLevel>>
ToLadder(this IObservable<MarketDepthLevel> source)
{
return source.Scan(ImmutableSortedDictionary<decimal, MarketDepthLevel>.Empty,
(lastLadder, depthLevel) =>
lastLadder.SetItem(depthLevel.Price, depthLevel));
}
}
ToLadder
扩展方法创建一个空的不可变梯形图作为种子聚合,并且每个连续的MarketDepthLevel
事件都会生成一个新的更新梯形图。 您可能想知道ImmutableSortedSet
是否足够。
您可能希望将其包装/投影到您自己的类型中,但希望您明白这一点。
最终,这仍然让您面临更新UI的挑战 - 如前所述,您现在已经陷入了整个阶梯,这意味着您必须每次绑定整个梯子,或者将其转换回个人流更新 - 它正在逐渐脱离主题以解决这个问题......!