【问题标题】:Selecting the correct range of values inside a function在函数内选择正确的值范围
【发布时间】:2011-06-06 08:54:00
【问题描述】:

我正在尝试创建一个自定义函数,它使用 tseries 包中的 drawdown 函数。我想将此函数应用于函数中正确的值范围,但即使这是一个相当新手的问题,我也看不到可能的解决方案。

这是我的数据框的样子:

> subSetTrades
   Instrument  EntryTime   ExitTime AccountValue
1         JPM 2007-03-01 2007-04-10         6997
2         JPM 2007-04-10 2007-05-29         7261
3         JPM 2007-05-29 2007-07-18         7545
4         JPM 2007-07-18 2007-07-19         7614
5         JPM 2007-07-19 2007-08-22         7897
6         JPM 2007-08-22 2007-08-28         7678
7         JPM 2007-08-28 2007-09-17         7587
8         JPM 2007-09-17 2007-10-17         7752
9         JPM 2007-10-17 2007-10-29         7717
10        JPM 2007-10-29 2007-11-02         7423
11        KFT 2007-04-13 2007-05-14         6992
12        KFT 2007-05-14 2007-05-21         6944
13        KFT 2007-05-21 2007-07-09         7069
14        KFT 2007-07-09 2007-07-16         6919
15        KFT 2007-07-16 2007-07-27         6713
16        KFT 2007-07-27 2007-09-07         6820
17        KFT 2007-09-07 2007-10-12         6927
18        KFT 2007-10-12 2007-11-28         6983
19        KFT 2007-11-28 2007-12-18         6957
20        KFT 2007-12-18 2008-02-20         7146

如果我手动计算我希望我的函数输出的值,结果是正确的:

# Apply the function to the dataframe
with(subSetTrades, tapply(AccountValue, Instrument, MDD_Duration))
JPM KFT 
106  85 
> # Check the function for JPM
> maxdrawdown(subSetTrades[1:10,4])$from
[1] 5
> maxdrawdown(subSetTrades[1:10,4])$to
[1] 10
> # Get the entry time for JPM on row 5
> # Get the exit time for JPM on row 10
> # Calculate the time difference
> difftime(subSetTrades[10,3], subSetTrades[5,2], units='days')
Time difference of 106 days
# Check the calculations for the other Instrument
> maxdrawdown(subSetTrades[11:20,4])$from
[1] 3
> maxdrawdown(subSetTrades[11:20,4])$to
[1] 5
> # Get the exittime on row 5 for KFT, get the entrytime for KFT on row 3, 
# and calculate the time difference
> difftime(subSetTrades[15,3], subSetTrades[13,2])
Time difference of 67 days

正如您在上面的示例中看到的,我的自定义函数 (MDD_Duration) 为 JPM 提供了正确的值,但为 KFT 提供了错误的值:结果应该是 67,而不是 85。函数 MDD_Duration 如下:

MDD_Duration <- function(x){
    require(tseries)
    # Get starting point
    mdd_Start <- maxdrawdown(x)$from
    mdd_StartDate <- subSetTrades$EntryTime[mdd_Start]
    # Get the endpoint
    mdd_End <- maxdrawdown(x)$to
    mdd_EndDate <- subSetTrades$ExitTime[mdd_End]
    return(difftime(mdd_EndDate, mdd_StartDate, units='days'))
}

手动追溯此自定义函数的步骤显示“from”和“to”行号的计算存在问题(即 R 需要根据仪器的长度调整 KFT 的值在它之前,在这种情况下是 JPM)。对于可能的解决方案,R 需要执行以下操作:

如果该工具是第一个(即在列表顶部),则获取 maxdrawdown 函数的“来自”值。但是,如果当前乐器是第二个(或第三个等),则考虑前一个乐器的长度。因此,如果工具 JPM 的长度为 10,则搜索 KFT 的值应从 +10 开始。并且寻找仪器 3 的 fromto 值应该从仪器 1 的长度 + 仪器 2 的长度开始。

我尝试在函数中使用nrow(这似乎是这个答案的明显解决方案),这导致了关于“长度为 0 的参数”的错误,即使 nrow 使用正确(即函数外部的相同语句确实工作)。我还尝试对函数内的数据进行子集化,但也没有成功。任何想法都非常受欢迎。 :)

【问题讨论】:

    标签: function r subset


    【解决方案1】:

    split 是你的朋友。如果我修改您的函数,使其期望具有三个感兴趣的变量(AccountValue、EntryTime、ExitTime)的数据框,如下所示:

    MDD_Duration <- function(x){
        # require(tseries)
        # Get starting point
        mdd_Start <- maxdrawdown(x$AccountValue)$from
        mdd_StartDate <- x$EntryTime[mdd_Start]
        # Get the endpoint
        mdd_End <- maxdrawdown(x$AccountValue)$to
        mdd_EndDate <- x$ExitTime[mdd_End]
        return(difftime(mdd_EndDate, mdd_StartDate, units='days'))
    }
    

    我们可以将其应用于您的数据的拆分版本:

    > sapply(split(subSetTrades[,-1], subSetTrades[,1]), MDD_Duration)
    JPM KFT 
    106  67
    

    看看split 对您的数据做了什么可能会有所帮助:

    > split(subSetTrades[,-1], subSetTrades[,1])
    $JPM
        EntryTime   ExitTime AccountValue
    1  2007-03-01 2007-04-10         6997
    2  2007-04-10 2007-05-29         7261
    3  2007-05-29 2007-07-18         7545
    4  2007-07-18 2007-07-19         7614
    5  2007-07-19 2007-08-22         7897
    6  2007-08-22 2007-08-28         7678
    7  2007-08-28 2007-09-17         7587
    8  2007-09-17 2007-10-17         7752
    9  2007-10-17 2007-10-29         7717
    10 2007-10-29 2007-11-02         7423
    
    $KFT
        EntryTime   ExitTime AccountValue
    11 2007-04-13 2007-05-14         6992
    12 2007-05-14 2007-05-21         6944
    13 2007-05-21 2007-07-09         7069
    14 2007-07-09 2007-07-16         6919
    15 2007-07-16 2007-07-27         6713
    16 2007-07-27 2007-09-07         6820
    17 2007-09-07 2007-10-12         6927
    18 2007-10-12 2007-11-28         6983
    19 2007-11-28 2007-12-18         6957
    20 2007-12-18 2008-02-20         7146
    

    只要您有一个函数可以接受并使用您的数据集的数据框/子集,我们就可以使用split 来形成子集,并使用lapplysapply 将我们的函数应用于那些子集。

    您可能希望将其合并到您的函数MDD_Duration()

    MDD_Duration2 <- function(x){
        FUN <- function(x) {
            # Get starting point
            mdd_Start <- maxdrawdown(x$AccountValue)$from
            mdd_StartDate <- x$EntryTime[mdd_Start]
            # Get the endpoint
            mdd_End <- maxdrawdown(x$AccountValue)$to
            mdd_EndDate <- x$ExitTime[mdd_End]
            return(difftime(mdd_EndDate, mdd_StartDate, units='days'))
        }
        sapply(split(x, droplevels(x[, "Instrument"])), FUN)
    }
    

    我们在x[, "Instrument"]) 上使用新的(在 R 2.12.x 中)函数 droplevels 以允许该函数工作,即使我们有单级数据或对数据子集进行操作:

    > MDD_Duration2(subSetTrades)
    JPM KFT 
    106  67 
    > MDD_Duration2(subSetTrades[1:10,])
    JPM 
    106
    

    【讨论】:

    • 我的原始结果与@Jura25 之间的差异是由于我在从帖子中读取数据时忘记将EntryTimeExitTime 转换为"Date" 类的对象。我已经对更正的数据重新运行了我的答案,它现在复制了 @Jura25 的结果。
    • 感谢 Gavin,这很有魅力!还要感谢您清楚地说明了split 的使用,这有助于理解。我喜欢您在 MDD_Duration 函数中的 droplevel 语句,并将其合并到我的脚本中。谢谢! :)
    猜你喜欢
    • 2021-08-18
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-01
    相关资源
    最近更新 更多