我在Mongo DB中导入的一些市场数据上有1分钟OHLC条。
每个文档都是这样的:
{
"_id" : ObjectId("5ac3163f31a0632c7642ca1c"),
"Date" : "08/06/2007",
"Time" : "15:01",
"Open" : 1310,
"High" : 1310.25,
"Low" : 1309.5,
"Close" : 1310,
"Up" : 209,
"Down" : 165,
"Volume" : 0
}
我想构建一个允许我从这些数据中快速生成X-bar间隔的函数。即生成输出5分钟柱,1小时柱,每日柱等...我还希望能够过滤掉数据范围。
我一直在玩Mongo的聚合函数,但是我不知道如何处理这个以及我应该如何订购管道操作。
我是先按'日期'分组,然后按'时间'排序,再按$ first,$ last,$ max和$ min分组?
或者我首先以某种方式创建一个新的字段,将“日期”和“时间”结合起来然后进行分组?
虽然我不需要首先以某种方式将“Date”和“Time”字段从字符串转换为Date字段,以便Mongo知道如何正确排序和匹配? ......但是那时我会做哪个订单呢?
我仍然是MongoDB的新手,所以任何建议都会受到赞赏。
答案 0 :(得分:1)
好的,我想出了一个解决方案:
db.minbars.aggregate([
{
$project:
{
dts:
{
$dateFromString:
{
dateString:
{
$concat: ['$Date', '$Time']
}
}
},
Open:1,
High:1,
Low:1,
Close:1
}
},
{
$match:
{
dts:
{
$gte: ISODate("2016-01-01T00:00:00.000Z"),
$lte: ISODate("2016-12-31T00:00:00.000Z")
}
}
},
{
$sort: { dts : 1 }
},
{
$group:
{
_id:
{
year: {$year: "$dts"},
month: {$month: "$dts"},
day: {$dayOfMonth: "$dts"},
hour: {$hour: "$dts"},
min:
{
$add:
[
{$subtract:
[
{$minute: "$dts"},
{$mod: [{$minute: "$dts"}, 5]}
]},
5
]
}
},
Open: {$first: "$Open"},
High: {$max: "$High"},
Low: {$min: "$Low"},
Close: {$last: "$Close"}
}
}
], {allowDiskUse: true})
以下是每个管道阶段的解释:
使用'dateFromString'将'Date'和'Time'组合成一个ISODate对象('dts' - 代表日期时间戳)。保留其他OHLC字段。
根据日期范围过滤掉
按新的ISODate对象排序('dts')。
将具有相同年,月,日,小时和5分钟间隔的所有文档组合在一起。分钟间隔使用公式: minute = minuteIn - (minuteIn%i)+ i,其中i =分钟间隔。我正在添加'i',以便将分钟00,01,02,03和04聚合到下一个05分钟的间隔(而不是之前的00分钟间隔)。注意:如果你想要1小时,4小时,每日酒吧等等,那么你需要相应地调整_id部分。
注意: 我在这里使用{allowDiskUse:true}因为我曾经在Sort阶段遇到了Memory约束。
也许有人可以想出一个更简单的方法来做到这一点?
更新:
正如我在上面4)中所提到的,我提到我在结果分钟中添加了“i”(分钟间隔)。然而,当我这样做时,我最终在输出中出现了'60'分钟的间隔。你应该只有0,5,10,15,... 55分钟的酒吧,不应该有60分钟的酒吧。所以这不正确。
此外,如果您与交易平台(即Thinkorswim)进行比较,您可以看到标准做法是使用前5分钟间隔作为条形图的时间戳。例如,5分钟栏9:25表示这些分钟栏的聚合:9:25,9:26,9:27,9:28,9:29。
答案 1 :(得分:0)
我认为,你可以简单地使用PHP。 要降低代码的复杂性,请不要创建包含日期和时间的新字段。
$outputs = array();
$raw_datas = array();
foreach($raw_datas as $data){
$date = \DateTime::createFromFormat('D/M/Y H:i', $data["Date"]." ".$data["Time"]);
$outputs['daily'][$date->format("D/M/Y")][] = $date; //or $date.id if you aim to use AJAX later
$outputs['hourly'][$date->format("D/M/Y H")][] = $date; //or $date.id if you aim to use AJAX later
// And so on...
// ....
}
return $outputs;
不幸的是,如果你想多次生成这个图,你可以添加一个字段时间(包含时间戳)!
答案 2 :(得分:0)
您需要按日期和时间进行分组(准确的时间间隔)。请查看https://docs.mongodb.com/ecosystem/use-cases/storing-log-data/#counting-requests-by-day-and-page以获取管道和StackOverflow本身的示例 - 类似的问题已经多次回答,例如Group result by 15 minutes time interval in MongoDb
如果您需要快速生成X-bar间隔,并且数据集足够大,聚合速度明显变慢,则可能需要预先聚合数据。该模式在https://www.mongodb.com/blog/post/schema-design-for-time-series-data-in-mongodb和https://docs.mongodb.com/ecosystem/use-cases/pre-aggregated-reports-mmapv1/中有详细描述(如果您使用的是WiredTiger引擎,则忽略预分配部分)