MongoDB:股票报价数据聚合
我正在使用MongoDB来存储我的股票交易数据。每分钟我会为每个股票符号存储一个文档:
{
"_id" : ObjectId("535fb330f6a03d59077db43c"),
"symbol" : "AAPL",
"ts_minute" : ISODate("2014-04-29T14:12:00Z"),
"ticks" : [
{
"mu" : 115864,
"ae" : true,
"t" : 2,
"v" : 571.93
},
{
"mu" : 803378,
"ae" : true,
"t" : 2,
"v" : 571.91
},
{
"mu" : 903378,
"ae" : false,
"t" : null,
"v" : 9000
}
}
这里的mu
表示自ts_minute
以来的微秒数,t
是交易类型(比如买入、卖出、开盘、收盘、成交量等),而v
是具体的数值。
为了把这些数据整理成每分钟的OHLC(开盘、最高、最低、收盘)数据,我使用了以下代码(用的是PyMongo):
query = {'$match': {'symbol': 'AAPL'}}
projection = {
'$project': {
'symbol': 1,
'year': {'$year': '$ts_minute'},
'month': {'$month': '$ts_minute'},
'day': {'$dayOfMonth': '$ts_minute'},
'hour': {'$hour': '$ts_minute'},
'minute': {'$minute': '$ts_minute'},
'ts_minute': 1,
'ticks': 1
}
}
unwind = {'$unwind': '$ticks'}
sort = {'$sort': {'ts_minute': 1}}
group = {
'$group': {
'_id': {
'symbol': '$symbol',
'year': '$year',
'month': '$month',
'day': '$day',
'hour': '$hour',
'minute': '$minute'
},
'open': {'$first': '$ticks.v'},
'high': {'$max': '$ticks.v'},
'low': {'$min': '$ticks.v'},
'close': {'$last': '$ticks.v'},
}
}
bars = tick_collection.aggregate([query, projection, unwind, sort, group])
问题是,我把成交量的交易数据和价格的交易数据存储在同一个数组里。成交量的交易数据是通过t
等于null
来识别的。所以当我进行分组时,价格数据和成交量数据就会混在一起。我想把数据整理成OHLCV,其中OHLC是基于t
不等于null
的部分,而V应该是数组中最后一个t
等于null
的元素。
这样说清楚了吗?还是说这只是个糟糕的设计?;-)
1 个回答
2
为了提高性能,你真的需要把 $sort
放在 unwind
之前。这样它会和 $match
一起处理,并且会使用合适的索引(希望你有 {symbol:1,ts_minute:1} 这个索引)。而 project
应该在 unwind
之后进行,这样才能创建你需要的价格和交易量字段,以便进行聚合。看起来你应该直接按 ts_minute 来分组。需要做的改动是:
query = {'$match': {'symbol': 'AAPL'}}
sort = {'$sort': {'ts_minute': 1}}
unwind = {'$unwind': '$ticks'}
projection = {
'$project': {
'symbol': 1,
'ts_minute': 1,
'volume' : { '$cond' : [
{"$eq" : ["$ticks.t",null]},
"$ticks.v",
0
] },
"price" : { "$cond" : [
{"$eq" : ["$ticks.t",null] },
null,
"$ticks.v"
] }
}
}
group = {
'$group': {
'_id': {
'symbol': '$symbol',
'minute': '$ts_minute'
},
'open': {'$first': '$price'},
'high': {'$max': '$price'},
'low': {'$min': '$price'},
'close': {'$last': '$price'},
'volume': {'$sum': '$volume'}
}
}
bars = tick_collection.aggregate([query, sort, unwind, projection, group])