【问题标题】:MongoDB: Aggregation of stock tick dataMongoDB:股票报价数据的聚合
【发布时间】:2014-06-19 06:28:56
【问题描述】:

我正在使用 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

这有意义吗?还是只是糟糕的架构设计? ;-)

【问题讨论】:

  • 您的 group 子句不应该也包含“ticks.t”作为“_id”的一部分吗?不知道为什么你在分组前进行排序,可能是你应该在基于分组阶段生成的“_id”之后,通过“_id”和“_id.t”的其他组件组合排序(来自ticks.t ) 可能会给你你想要的。
  • 那么这里的问题到底是什么?您是在问如何将其与您拥有的架构分开吗?您是否还想要“量”刻度的离散结果?如果是这样,那是什么?
  • 你对这个集合有什么索引?
  • 看起来你的 ts_minute 已经是一整分钟了 - 为什么要把它分解成更多的子部分?还是它实际上会记录秒数?
  • 我认为 Asya 的回答很到位。我的查询基于slideshare.net/mongodb/… slide #26,这就是为什么我在分组之前排序。我在symbolts_minute 上有索引。

标签: python mongodb pymongo aggregation-framework


【解决方案1】:

为了提高性能,您确实需要将 $sort 移动到展开之前 - 它将与 $match 结合并使用适当的索引(这将是 {symbol:1,ts_minute:1} 所以我希望您有该索引可用)。该项目应该在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])

【讨论】:

    猜你喜欢
    • 2011-03-15
    • 2014-06-05
    • 2020-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-28
    • 2011-02-09
    相关资源
    最近更新 更多