【问题标题】:Caching in a high-performance financial application在高性能金融应用程序中缓存
【发布时间】:2012-10-04 10:04:23
【问题描述】:

我正在编写一个应用程序,其目的是优化交易策略。为简单起见,仅假设我们有一个交易策略,即“在此处进入”,然后是“在交易中退出”,然后让我们有两个模型:一个说我们应该承担多少风险(如何如果我们站在市场的错误一边,我们会损失多少),另一个说我们应该获得多少利润(即,如果市场同意,我们将获得多少利润)。

为简单起见,我将历史已实现交易称为即时报价。这意味着如果我“在第 28 次交易时输入”,这意味着我将在我的数据集中的第 28 次交易时以该交易的价格输入交易。刻度按时间顺序存储在我的数据集中。

现在,假设整个数据集的进入策略有 500 个条目。对于每个条目,我可以预先计算确切的条目刻度。我还可以计算每个入口点的退出策略所确定的退出点(同样作为刻度数)。对于每个条目,我还可以预先计算建模的损失和利润以及这些损失或利润会受到打击的分时。剩下要做的最后一件事是计算首先会发生什么,即退出策略、退出亏损或退出盈利。

因此,我遍历交易数组并计算 exitTick[i] = min(exitTickByStrat[i], exitTickByLoss[i], exitTickByProfit[i])。整个过程非常缓慢(假设我这样做了 100M 次)。我怀疑缓存未命中是罪魁祸首。问题是:这能以某种方式更快吗?我必须遍历 4 个非平凡长度的数组。我提出的一个建议是将数据分组为四个元组,即具有一组结构,例如(entryTick、exitOnStrat、exitOnLoss、exitOnProfit)。由于更好的缓存可预测性,这可能会更快,但我不能肯定地说。为什么到目前为止我还没有测试它是因为检测分析器在某种程度上不适用于我的应用程序的发布二进制文件,而采样分析器在我看来是不可靠的(我已经尝试过英特尔的分析器)。

所以最后的问题是:这个问题可以做得更快吗?使用发布二进制文件进行内存分析的最佳分析器是什么?我在Win7,VS2010上工作。

编辑: 非常感谢大家。我试图尽可能地简化我原来的问题,因此造成了混乱。只是为了确保它的可读性 - 目标意味着预期/已实现的利润,止损意味着预期/已实现的损失。

优化器是蛮力的。所以,我有一些策略设置(例如指标周期等),然后是最小/最大 breakEvenAfter/breakEvenBy,然后是为您提供止损/目标值的公式。这些公式也是优化的对象。因此,我有一个优化结构,如

for each in params
{
   calculateEntries()
   for each in beSettings
   {
      precalculateBeData()
      for each in targetFormulaSettings
      {
          precalculateTargetsAndRespectiveExitTicks
          for each in stopFormulaSettings
          {
              precalulcateStopsAndRespectiveExitsTicks
              evaluateExitsAndDetermineImprovement()
          }
       }
    }
}

所以我尽可能地预先计算一些东西,并且只在我需要的时候计算一些东西。在 30 秒中,计算在 evaluateExitsAndDetermineImprovement() 函数中花费了 25 秒,该函数完成了我在原始问题中描述的操作,即选择 min(exitOnPattern, exitOnStop, exitOnTarget)。我需要调用函数 100M 次的原因是因为我有 100M 的所有参数组合。但在最后一个 for 循环中,只有 exitOnStops 数组发生变化。如果有帮助,我可以发布一些代码。感谢所有的cmets!

【问题讨论】:

  • “我怀疑缓存未命中是罪魁祸首”:不要怀疑。措施。 linux下使用CacheGrind,windows下换操作系统。

标签: c++ caching memory memory-profiling


【解决方案1】:

我对交易策略了解不多,但我通常会做一些优化。 嗯,有很多优化方法。 比如,容器类型,使用不同的 min 函数(我认为 boost 的函数比 stl 库中的函数快一些),尝试减少相同的计算等。 您还可以通过使用更快的函数来提高速度,或通过重新设计您的算法来进行优化。

对于性能分析,我在 Win7 x64 下使用 GlowCode,发布版本也可以。

【讨论】:

  • 谢谢,我会研究 GlowCode。
  • 我认为(假设所有函数都执行得很快)这仅仅是因为计算量很大,需要这么长时间。 IE。你说它需要大约 30 秒才能完成,执行 100M 次迭代,这意味着 0.0003 毫秒/步。所以我看到的唯一优化就是以某种方式减少迭代次数。编辑:也许具体的代码可以帮助我们
  • 嗨,弗雷德。谢谢回复。英特尔分析器输出表明,每次运行大约 5 秒(即 30 秒)用于仅从数组中获取数据的函数(如 prelcalcedValues[tradeIndex][profitIndex]),这就是我认为缓存未命中是主要问题的原因。我将使用 GlowCode 进行分析,如果我发现新的东西,我会很高兴发布解决方案。谢谢!
【解决方案2】:

也许我完全误解了你的系统,但是:
您“预先计算”的内容是什么以及何时以及为什么 100M 次???

我不知道它是否会对您有所帮助,但它可能会显着简化您的系统 - 有 2 种常见的交易策略:(描述是我的,不是官方的)
1) “固定点退出” - 当交易发生时,所有退出点都计算一次,并定期检查市场条件/价格。
2) “可变点退出” - 当市场移动时,退出点被重新计算(通常是为了锁定更多利润/减少损失)。

在情况 1) 实际计算只发生一次,所以它应该 非常 快
在情况 2) 每次都会进行计算,但可以通过许多不同的方式对其进行优化 - 其中之一是您可以存储按退出点索引的交易,并且只获取并重新计算接近实际市场情况的交易。

我不确定您指的是哪个缓存未命中?你数据缓存? CPU缓存?

【讨论】:

  • 您好 Germann,为了更清晰,我编辑了我的原始帖子。谢谢!
【解决方案3】:

所以,经过一番努力,我理解了 Alexandre C 的建议。当我运行缓存未命中分析时,我发现在评估Exits() 函数的 15M 调用中,我只有 30K 缓存未命中,因此该函数的性能不受缓存的阻碍。因此,我不得不“开始相信”VTune 实际上产生了有效的结果,尽管很奇怪。由于 VTune 输出的分析与当前线程的名称不匹配,我决定开始一个新的thread。谢谢大家的意见和建议。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-26
    • 2011-04-04
    • 1970-01-01
    • 2017-02-06
    • 2012-10-03
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多