在f#中创建期货合约的每小时头寸向量

时间:2013-10-04 11:15:18

标签: c# f#

我试图找出何时使用f#以及何时使用c#。我有能源交易的实际问题。电力合约报价为,交货开始,交货结束,关税,交易量。一个例子是,100MW Cal14 Offpeak,所以从2014年1月1日到2014年12月31日,如果工作时间在一周的20到8(夜间)或周末的所有时间,合同每小时可以提供100MW - 总计约5500小时。高峰合同在工作日提供8-20个,而Base提供所有小时数。

如果您有这些合约的投资组合,您希望将它们汇总为每小时位置向量。到目前为止我的代码在这里:

合同数据示例(包含Excel格式的日期):

let data = [(41275., 41639., "Base", 10.); (41275., 41639., "Base", 60.); (41275., 41639., "Peak", 20.); (41275.,41639.,"Offpeak",30.);  (41275.,41364.,"Peak",40.); (41275.,41364.,"Peak",70.); (41275.,41364.,"Offpeak", 50.)]

汇总相同合同的功能:

let group_fold keys value fold acc seq =
    seq |> Seq.groupBy keys 
        |> Seq.map (fun ((key1, key2, key3), seq) -> 
            (key1, key2, key3, seq |> Seq.map value |> Seq.fold fold acc))


let aggrTrades data =
data |> group_fold (fun (k1, k2, k3, _) -> k1, k2, k3) (fun (_, _, _, v) -> v) (+) 0.0

识别峰值和非峰值时间的功能:

let poindicator dts =
    let newdts = DateTime.FromOADate dts
    // Match on day of week and hour properties of the date time
    match newdts.DayOfWeek, newdts.Hour with
    // For weekend, return false
    | DayOfWeek.Saturday, _ | DayOfWeek.Sunday, _ -> false
    // For working hours, return true
    | _, h when h >= 8 && h < 20 -> true
    // For non-working weekday hours, return false
    | _ -> false

最后一个函数将它们放在一起并创建一个小时向量(std =每小时向量的开始日期和edd =结束日期):

let hourlyvec data std edd =
    let aggrdata = aggrTrades data
    let dtsvec = [std.. 1./24. .. edd]
    let nrhrs = dtsvec |> Seq.length
    let mutable res = Seq.init nrhrs (fun i -> 0.0)
    for i=0 to res |> Seq.length do
        for (a, b, c, d) in aggrdata do
            match a , b with
            | e, f when e <= dtsvec.[i] && f >= dtsvec.[i] -> 
                match c with
                | "Base" -> res.[i] <- res.[i] + d
                | "Peak" when poindicator (DateTime.FromOADate dtsvec.[i]) -> res.[i] <- res.[i] + d
                | "Offpeak" when not poindicator (DateTime.FromOADate dtsvec.[i]) -> res.[i] <- res.[i] + d
                | _ -> failwith "Not recognized tarif"
            |_ -> failwith "Not in period tarif"
    dtsvec, res

这与FS0039失败:字段,构造函数或成员'Item'未定义,似乎也不喜欢嵌套的伪指标函数

任何指针都会非常感激吗?另外如果您认为这在c#中会更容易,请告诉我,我认为它是一个功能性问题所以我先去了f#。

2 个答案:

答案 0 :(得分:2)

问题出在这里

    match a , b with
    | e, f when e <= dtsvec.[i] && f >= dtsvec.[i] -> ...

如果不满足条件,您将收到匹配失败异常,编译器会正确发出警告。

这里永远不会有效

        match _, _, c, _ with
        | "Base" -> res.[i] <- res.[i] + d
        | "Peak" when poindicator DateTime.FromOADate dtsvec.[i] -> res.[i] <- res.[i] + d
        | "Offpeak" when not poindic DateTime.FromOADate dtsvec.[i] -> res.[i] <- res.[i] + d
        | _ -> failwith "Not recognized tarif"

因为您只能将_放在|之后不在match ... with

中的部分中

答案 1 :(得分:0)

我希望你能将这个问题重新发布到Code Review StackExchange,但是既然你没有,我会在这里发布我的简化版代码,以防OP或未来的访问者发现它有用:

let group_fold keys valueExtractor folder state seq =
    seq
    |> Seq.groupBy keys
    |> Seq.map (fun ((key1, key2, key3), seq) ->
        let finalState =
            (state, seq)
            ||> Seq.fold (fun state v ->
                let mappedValue = valueExtractor v
                folder state mappedValue)
        key1, key2, key3, finalState)

let poindicator dts =
    let newdts = DateTime.FromOADate dts

    // Match on day of week and hour properties of the date time
    // For weekend, return false
    newdts.DayOfWeek <> DayOfWeek.Saturday
    && newdts.DayOfWeek <> DayOfWeek.Sunday
    // For working hours, return true
    // For non-working weekday hours, return false
    && newdts.Hour >= 8
    && newdts.Hour < 20

let aggrTrades data =
    data |> group_fold (fun (k1, k2, k3, _) -> k1, k2, k3) (fun (_, _, _, v) -> v) (+) 0.0

let hourlyvec data std edd =
    let dtsvec = [|std.. 1./24. .. edd|]

    let res =
        let nrhrs = Array.length dtsvec
        let aggrdata = aggrTrades data

        Array.init nrhrs <| fun i ->
            (0.0, aggrdata)
            ||> Seq.fold (fun periodValue (a, b, c, d) ->
                match a, b with
                | e, f when e <= dtsvec.[i] && f >= dtsvec.[i] -> 
                    match c with
                    | "Base" ->
                        periodValue + d
                    | "Peak" when poindicator dtsvec.[i] ->
                        periodValue + d
                    | "Offpeak" when not (poindicator dtsvec.[i]) ->
                        periodValue + d
                    | _ ->
                        failwith "Not in Tarif"
                |_ ->
                    failwith "Not in period")

    dtsvec, res