在 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#。
所以问题就在这里
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