F# 将日期范围窗口应用于数据的时间序列

F# 将日期范围窗口应用于数据的时间序列,f#,F#,我正在写一个程序,试图从timeseries的一组股票交易想法中获得价值。它们位于下面的quotedTrade对象数组中(使用JSONSerializer从磁盘获取数据),按startOn日期字段排序: [<DataContract>] type trade = { [<field: DataMember(Name="tradeId") >] tradeId : int ; [<field: Dat

我正在写一个程序,试图从timeseries的一组股票交易想法中获得价值。它们位于下面的quotedTrade对象数组中(使用JSONSerializer从磁盘获取数据),按startOn日期字段排序:

    [<DataContract>] 
    type trade = {
        [<field: DataMember(Name="tradeId") >] 
        tradeId : int ;
        [<field: DataMember(Name="analystId") >] 
        analystId: int
        [<field: DataMember(Name="startOn") >] 
        startOn : System.DateTime ;
        [<field: DataMember(Name="endOn") >] 
        endOn : System.DateTime option ;
        [<field: DataMember(Name="tradeType") >] 
        tradeType : string ;
        [<field: DataMember(Name="securityId") >] 
        securityId : int ;
        [<field: DataMember(Name="ricCode") >] 
        ricCode : string ;
        [<field: DataMember(Name="yahooSymbol") >] 
        yahooSymbol : string ;
        [<field: DataMember(Name="initialPrice") >] 
        initialPrice : float ;
    }

    [<DataContract>] 
    type quotedTrade = {
        [<field: DataMember(Name="trade") >] 
        trade : trade ;
        [<field: DataMember(Name="q7") >] 
        q7: float
        [<field: DataMember(Name="q14") >] 
        q14: float
        [<field: DataMember(Name="q21") >] 
        q21: float
    }
然后以某种方式对它们进行过滤(sliceByAnalyst、sliceByTicker将在稍后提供-尽管我正在考虑使用Array.Map、Array.filter函数,希望您提供一个干净的解决方案)

主要问题是关于应用滑动窗口:

// iterate over each analyst
for tradeByAnalyst in tradesByAnalyst do
    // look at trades on a per analyst basis
    let mySeries : quotedTrade array= tradeByAnalyst.trades
    // each window is an array of trades that occured in a seven day period
    let sevenDayWindowsByAnalyst : quotedTrade array = sliceByDays 7 mySeries
    // I want to evaluate the seven day window, per this analsyt independently
    for sevenDayWindowByAnalyst in sevenDayWindowsByAnalyst do
        let someResult = doSomethingWithTradesInWindow sevenDayWindowByAnalyst
关键是我有一个每个分析师的数据集,其中第0天的单笔交易表示为:T0,第1天的单笔交易表示为:T1;我的原始集合包含第0天的3笔交易,以及以下日期后第1、3、5、8、10周的单个交易:

[ T0 T0 T0 T1 T3 T5 T8 T10 ]
返回

[
  [ T0 T0 T0 T1 T3 T5 ] // incudes T0 -> T6
  [ T1 T3 T5 ] // incudes T1 -> T7
  [ T3 T5 T8 ] // incudes T2 -> T8
  [ T3 T5 T8 ] // incudes T3 -> T9
  [ T5 T8 T10 ] // incudes T4 -> T10
  [ T5 T8 T10 ] // incudes T5 -> T11
  [ T8 T10 ] // incudes T6 -> T12
  [ T8 T10 ] // incudes T7 -> T13
  [ T8 T10 ] // incudes T8 -> T14
  [ T10 ] // incudes T9 -> T15
  [ T10 ] // incudes T10 -> T16
]

任何关于实现这一目标的最佳方法的想法都将不胜感激

首先,关于您的第一个问题-如何断开数据-您还可以使用
Seq
模块中的函数(它们适用于任何集合类型,如列表、数组等)。要将数据分组,可以很好地使用
Seq.groupBy

trades 
  |> Seq.groupBy (fun qt -> qt.trade.analystId)
  |> Seq.map (fun (key, values) -> 
        { analystId = key; trades = values |> Array.ofSeq )
可以使用
Seq
功能(如
filter
map
)再次对数据进行进一步处理。如果您想让代码更通用(还有一些函数在
数组
中不可用),我认为这些函数比
数组
的函数更可取。但是,来自
数组的函数要快一点(对于较大的数据量,这可能很重要)

在关于滑动窗口的问题中,我不完全理解您的数据表示是什么。但是,如果您拥有(或可以构建)所有交易的列表(例如,为每个分析师键入
list
,则您可以使用
Seq.windowed

trades 
  |> Seq.windowed 7
  |> Seq.map (fun win ->
      // all trades in the window as an array are in 'win' 
     )

函数
windowed
仅创建指定长度的窗口(较短的窗口将被删除),因此这并不完全符合您的要求。但是,我想您可以使用空交易填充数据来解决此问题。

首先,关于您的第一个问题-如何分解数据-您还可以使用
Seq
模块中的函数(它们可用于任何集合类型,如列表、数组等)。要将数据分组,可以很好地使用
Seq.groupBy

trades 
  |> Seq.groupBy (fun qt -> qt.trade.analystId)
  |> Seq.map (fun (key, values) -> 
        { analystId = key; trades = values |> Array.ofSeq )
数据的进一步处理可以使用
Seq
函数(如
filter
map
)再次完成。如果您想让代码更通用,我认为这些函数比
Array
函数更可取(还有一些函数在
Array
中不可用)。但是,
数组
中的函数要快一点(对于较大的数据量,这可能很重要)

在关于滑动窗口的问题中,我不完全理解您的数据表示形式。但是,如果您有(或可以构建)所有交易的列表(例如,为每个分析师键入
list
,那么您可以使用
Seq.windowed

trades 
  |> Seq.windowed 7
  |> Seq.map (fun win ->
      // all trades in the window as an array are in 'win' 
     )

函数
windowed
只创建指定长度的窗口(较短的窗口被删除),因此这并不能完全满足您的需要。但是,我想您可以用空交易填充数据来解决这个问题。

我想您可能可以这样做来获得您关心的交易:

let sliceByDays n (qts : quotedTrade seq) =
  let dates = qts |> Seq.map (fun qt -> qt.trade.startOn)
  let min = dates |> Seq.min
  let max = dates |> Seq.max
  let days = min |> Seq.unfold (fun d -> if d > max then None else Some(d, d.AddDays(1.)))
  [for d in days do
     let tradesInRange =
       qts
       |> Seq.filter (fun qt -> qt.trade.startOn >= d && qt.trade.startOn < d.AddDays(float n))
     yield tradesInRange]
let sliceByDays n(qts:quotedTrade seq)=
让dates=qts |>Seq.map(fun qt->qt.trade.startOn)
设min=dates |>Seq.min
设max=dates |>Seq.max
让days=min |>Seq.unfold(乐趣d->如果d>max,那么其他的就没有了(d,d.AddDays(1.))
[d在几天内完成
让贸易扩大=
qts
|>Seq.filter(fun qt->qt.trade.startOn>=d&&qt.trade.startOn

这会给你一个交易序列的列表,每天一个序列。

我想你可以这样做来获得你关心的交易:

let sliceByDays n (qts : quotedTrade seq) =
  let dates = qts |> Seq.map (fun qt -> qt.trade.startOn)
  let min = dates |> Seq.min
  let max = dates |> Seq.max
  let days = min |> Seq.unfold (fun d -> if d > max then None else Some(d, d.AddDays(1.)))
  [for d in days do
     let tradesInRange =
       qts
       |> Seq.filter (fun qt -> qt.trade.startOn >= d && qt.trade.startOn < d.AddDays(float n))
     yield tradesInRange]
let sliceByDays n(qts:quotedTrade seq)=
让dates=qts |>Seq.map(fun qt->qt.trade.startOn)
设min=dates |>Seq.min
设max=dates |>Seq.max
让days=min |>Seq.unfold(乐趣d->如果d>max,那么其他的就没有了(d,d.AddDays(1.))
[d在几天内完成
让贸易扩大=
qts
|>Seq.filter(fun qt->qt.trade.startOn>=d&&qt.trade.startOn

这将为您提供一个交易序列列表,每天一个序列。

Seq.windowed函数不满足我的需要-我相信tt按顺序分组(即列表中的下7个)。我需要的是一个函数,给定一天,它会获取7天内发生的所有交易。可能会创建一个日期列表,迭代它们,并使用filter函数中的currentDay将Seq.filter应用于列表-这将是一个解决方案…Seq.windowed函数不满足我的需要-我相信tt按顺序分组(即列表中的下一个7)。我需要的是一个函数,给定一天,它会获取7天内发生的所有交易。可能会创建一个天数列表(日期),迭代它们并使用filter函数中的currentDay将Seq.filter应用于列表-这将是一个解决方案…看起来它可能会起作用-稍后会尝试一下。谢谢!效果很好-除了我需要跟踪窗口,但调整非常简单。使用此技术的新代码比pr容易得多eviuos veriosn thxlook可能会起作用-稍后会尝试一下。谢谢!效果很好-只是我需要窗口拖尾,但是调整很简单。使用这种技术的新代码比以前的veriosn thx容易得多