【发布时间】:2011-02-19 23:47:41
【问题描述】:
我的问题:我正在尝试为货币交易者开发一个网络应用程序。该应用程序允许交易者输入或上传有关其交易的信息,我想根据用户输入的内容计算各种统计数据。
现在,通常我会为此使用关系数据库,但我有两个不适合关系数据库的要求,所以我尝试使用 couchdb。这两个问题是:1)首先,我有一个配套的桌面应用程序,用户可以使用它并使用 couchdb 的出色复制功能复制到站点;2)我希望允许用户能够定义自己的自定义跟踪交易并根据他们输入的内容生成结果。沙发的模式较少的性质在这里似乎很完美,但最终可能比听起来更难。 (我已经知道 couch 需要您提前定义视图,所以我只是计划将所有自定义属性粘贴到一个数组中,然后在视图中发出该数组并从那里进一步处理。)
我在做什么:现在我只是在沙发上发出由每个用户系统键入的每笔交易,并使用系统的密钥进行查询以获得每个系统的一系列交易。简单的。我目前没有使用 reduce 函数来计算任何统计信息,因为我无法弄清楚如何在不出现 reduce 溢出错误的情况下获得所需的一切。
这是从沙发上发出的行示例:
{"total_rows":134,"offset":0,"rows":[
{"id":"5b1dcd47221e160d8721feee4ccc64be",
"key":["80e40ba2fa43589d57ec3f1d19db41e6","2010/05/14 04:32:37 +0000"], null,
"doc":{
"_id":"5b1dcd47221e160d8721feee4ccc64be",
"_rev":"1-bc9fe763e2637694df47d6f5efb58e5b",
"couchrest-type":"Trade",
"system":"80e40ba2fa43589d57ec3f1d19db41e6",
"pair":"EUR/USD",
"direction":"Buy",
"entry":12600,
"exit":12700,
"stop_loss":12500,
"profit_target":12700,
"status":"Closed",
"slug":"101332132375",
"custom_tracking": [{"name":"signal", "value":"Pin Bar"}]
"updated_at":"2010/05/14 04:32:37 +0000",
"created_at":"2010/05/14 04:32:37 +0000",
"result":100}}
]}
在我的 rails 3 控制器中,我基本上只是填充了一系列交易,例如上面的交易,然后将相关数据提取到更小的数组中,我可以计算我的统计数据。
这是我要显示统计数据和所有交易的页面的显示操作:
def show
@trades = Trade.by_system(:startkey => [@system.id], :endkey => [@system.id, Time.now ])
@trades.each do |trade|
if trade.result > 0
@winning_trades << trade.result
elsif trade.result < 0
@losing_trades << trade.result
else
@breakeven_trades << trade.result
end
if trade.direction == "Buy"
@long_trades << trade.result
else
@short_trades << trade.result
end
if trade["custom_tracking"] != nil
@custom_tracking << {"result" => trade.result, "variables" => trade["custom_tracking"]}
end
end
end
我省略了一些其他正在发生的事情,但这就是我正在做的事情的要点。然后我在视图层计算东西以产生一些结果:
<% winning_long_trades = @long_trades.reject {|trade| trade <= 0 } %>
<% winning_short_trades = @short_trades.reject {|trade| trade <= 0 } %>
<ul>
<li>Total Trades: <%= @trades.count %></li>
<li>Winners: <%= @winning_trades.size %></li>
<li>Biggest Winner (Pips): <%= @winning_trades.max %></li>
<li>Average Win(Pips): <%= @winning_trades.sum/@winning_trades.size %></li>
<li>Losers: <%= @losing_trades.size %></li>
<li>Biggest Loser (Pips): <%= @losing_trades.min %></li>
<li>Average Loss(Pips): <%= @losing_trades.sum/@losing_trades.size %></li>
<li>Breakeven Trades: <%= @breakeven_trades.size %></li>
<li>Long Trades: <%= @long_trades.size %></li>
<li>Winning Long Trades: <%= winning_long_trades.size %></li>
<li>Short Trades: <%= @short_trades.size %></li>
<li>Winning Short Trades: <%= winning_short_trades.size %></li>
<li>Total Pips: <%= @winning_trades.sum + @losing_trades.sum %></li>
<li>Win Rate (%): <%= @winning_trades.size/@trades.count.to_f * 100 %></li>
</ul>
这会产生以下结果,除了一些事情之外,这正是我想要的:
- 总交易次数:134
- 获奖者:70
- 最大赢家(点数):1488
- 平均获胜(点数):440
- 失败者:58
- 最大输家(点数):-516
- 平均亏损(点):-225
- 盈亏平衡交易:6
- 多头交易:125
- 赢得多头交易:67
- 空头交易:9
- 赢得空头交易:3
- 总点数:17819
- 胜率(%):52.23880597014925
我想知道的是什么——最后是实际问题:我开始怀疑当用户有 5,000 笔交易而不是像本例中只有 134 笔交易时这种方法的效果如何。我预计大多数用户每年只有不到 200 笔交易,但有些用户每年可能会有几千笔交易。每年大概不超过5000个。现在似乎工作正常,但页面加载时间已经变得有点高,以我的口味。 (根据 Rails 日志生成页面大约需要 800 毫秒,其中大约 250 毫秒用于视图层。)我确定我最终会缓存这个页面,但我仍然需要在每次交易更新时重新生成页面,并且我不能让这个太慢。呜呜呜……
- 是否可以使用直接的 couchdb reduce 函数在此处执行类似操作?我假设把它交给沙发可能有助于处理更大的数据集。我不知道怎么做,但我想这并不意味着不可能。如果可能,任何提示都会有所帮助。
- 如果由于 reduce 约束而导致 reduce 不可用,我可以使用列表函数吗? couchdb 列表函数是否适合这种类型的计算?任何人都知道列表函数是否表现良好?任何提示我想要实现的计算类型会是什么样子?
- 我考虑了其他选项,例如在保存每笔交易时或每晚运行计算(如果必须),并将结果保存到统计文档中,然后我可以查询,以便提前完成所有处理。我希望这是最后的手段,因为那样我就不能像我真正想要的那样动态地过滤掉交易时间段。 (如果可以的话,我想要一个用户可以滑动的滑块,以仅使用 couchdb 中的 startkey 和 endkey 显示该时间段的交易。)
- 如果我应该在页面查看时继续在 rails 应用程序中运行计算,我可以做些什么来改进我当前的实现。我对 Rails、沙发和编程很陌生。我确信我可以在这里做得更好。我需要为每个统计数据创建一个数组还是有更好的方法来做到这一点。
我想我真的很想得到一些关于如何解决这个问题的建议。我希望将页面生成时间保持在最短,因为我预计这些页面是访问量最高的页面。我的直觉是,我需要在调用统计信息之前将统计信息计算转移到沙发上或运行统计信息,但我不确定。
最后:就像我上面提到的,使用沙发的主要原因之一是允许用户定义自己的东西来跟踪每笔交易。将数据放到沙发上是没有问题的,但是我如何能够获取 custom_tracking 数组并找到每个命名跟踪属性的获胜交易数。如果有人能给我任何暗示这样做的可能性,那就太好了。
非常感谢。非常感谢任何帮助。如果有人想为我解决这个问题,愿意花一些钱。 (不知道堆栈溢出是否允许。)
【问题讨论】:
标签: ruby statistics couchdb ruby-on-rails-3