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