在 f# 中从期货合约创建每小时仓位向量

本文关键字:每小时 创建 向量 | 更新日期: 2023-09-27 18:33:58

我试图弄清楚何时使用f#以及何时使用c#。我在能源交易中遇到了一个实际问题。电力合同报价为,交货开始,交货结束,关税,数量。一个例子是,100MW Cal14 Offpeak,所以从1/1/14到31/12/14,如果一小时在工作日或周末的所有时间之间,合同每小时交付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"未定义,并且似乎也不喜欢嵌套的 poindicator 函数

任何指示将不胜感激?另外,如果您认为这在 c# 中会容易得多,请告诉我,我认为这是一个功能问题,所以我首先选择了 f#。

在 f# 中从期货合约创建每小时仓位向量

所以问题就在这里

    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

我希望

你能将这个问题重新发布到代码审查 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