[R-SIG-Finance] apply a function to a data.frame column with condition

Enrico Schumann e@ @end|ng |rom enr|co@chum@nn@net
Fri Mar 7 08:55:00 CET 2025


On Thu, 06 Mar 2025, Arnaud Gaboury writes:

> 	On Thu, 2025-03-06 at 07:29 +0100, Enrico Schumann wrote:
>> On Wed, 05 Mar 2025, Arnaud Gaboury writes:
>> 
>> > I work with Binancer [1] and PMwR [2] packages to write a trading
>> > journal.
>> > Here is a sample of my data frame:
>> > portfolio <- data.frame(
>> >   symbol = c("BTCUSDT", "BTCUSDT", "ETHUBTC", "AAVEBTC",
>> > "ENAUSDT"),
>> >   time = c("2024-12-17 10:01:30", "2024-12-18 21:32:53", "2025-01-
>> > 02
>> > 10:34:49", "2025-01-02 11:14:43", "2025-01-02 11:15:22")
>> > )
>> > 
>> > I want to fetch the 'BTCUSDT' price for a specific time if the
>> > symbol
>> > of same row end with these 3 letters : 'BTC'. In my sample, it will
>> > be
>> > rows 3 and 4.
>> > Here is how I find BTCUSDT price for date 2025-01-02 10:34:49:
>> > 
>> > get_btc_price <- function(time) {
>> >   klines <- binance_klines('BTCUSDT', start_time = '2025-01-02
>> > 10:34:49', end_time = '2025-01-02 10:34:49')
>> > }
>> > 
>> > I was thinking of this code to write my new column BTCUSDT_price:
>> > 
>> > df <- portfolio %>%
>> >   mutate(
>> >     BTCUSDT_price = ifelse(str_detect(symbol, "BTC$"),
>> > map_dbl(time,
>> > get_btc_price), NA_real_)
>> >   )}
>> > 
>> > But the code returns:
>> > Error in `mutate()`:
>> > ℹ In argument: `BTCUSDT_price = ifelse(...)`.
>> > Caused by error in `map_dbl()`:
>> > ℹ In index: 1.
>> > Caused by error in `[.data.table`:
>> > ! Item 1 of j is 12 which is outside the column number range
>> > [1,ncol=0]
>> > 
>> > I have tried other workarounds but all give me errors.
>> > 
>> > Thank you for help
>> > 
>> > 
>> > [1]https://cran.r-project.org/web/packages/binancer
>> > [2]https://cran.r-project.org/web/packages/PMwR
>> > 
>> 
>> You want to compute a new column for your data.frame as
>> a function of two existing columns.
>> 
>> In base R, if you don't want to use a loop (and there
>> would be nothing wrong with a loop), you could use
>> 'mapply'; and then cbind the column to your data.frame:
>> 
>>     new.column <- mapply(
>>         function(symbol, time) {
>>             if (grepl("BTC$", symbol)) {
>>                 ## your get_price computation, using
>>                 ## 'symbol' and 'time'
>>                 paste("do something with", symbol, time)
>>                 
>>             } else
>>                 NA
>>         },
>>         portfolio$symbol,
>>         portfolio$time
>>     )
>
> I am sorry but I can't see where I shall put my df ? And my function to
> get BTC price:
> get_btc_price <- function(my_time) {
>     # my_time_ms <- as.integer(as.numeric(my_time) * 1000)
>     klines <- binance_klines("BTCUSDT", interval = '1h', start_time =
> as.Date(my_time), end_time = as.Date(my_time) + 1)
>     return(as.numeric(klines$close[[18]]))
> }
>
> Thank you for your help

Is the ticker you want to fetch data for always the
same?  If yes, then something like this could be
used. [I don't know/use binance, so with a 'dummy' of
your function.]

    get_btc_price <- function(my_time) {
        paste(42, my_time)
    }
    
    new.column <- mapply(
        function(symbol, mytime) {
            if (grepl("BTC$", symbol)) {
                get_btc_price(mytime)
            } else
                NA
        },
        portfolio$symbol,
        portfolio$time
    )

    ##                 BTCUSDT                  BTCUSDT 
    ##                      NA                       NA 
    ##                 ETHUBTC                  AAVEBTC 
    ##"42 2025-01-02 10:34:49" "42 2025-01-02 11:14:43" 
    ##                 ENAUSDT 
    ##                      NA 


-- 
Enrico Schumann
Lucerne, Switzerland
https://enricoschumann.net



More information about the R-SIG-Finance mailing list