Basic demo of TSFrames using financial data

Create a TSFrame object for IBM historical data

To load the IBM historical data, we will use the MarketData.yahoo function from MarketData.jl, which returns the data in the form of a TimeArray. We just simply pass this on to the TSFrame constructor.

julia> using TSFrames, MarketData, Plots, Statistics
julia> ibm_ts = TSFrame(MarketData.yahoo(:IBM))13137×6 TSFrame with Date Index Index Open High Low Close AdjClose Volume Date Float64 Float64 Float64 Float64 Float64 Float64 ────────────────────────────────────────────────────────────────────────────── 1971-02-08 16.0851 16.336 15.8939 16.2882 3.75666 719648.0 1971-02-09 16.2882 16.3121 16.1687 16.1807 3.73186 673624.0 1971-02-10 16.1568 16.1568 15.9775 16.1209 3.71808 648520.0 1971-02-11 16.1209 16.2285 16.097 16.1926 3.73461 579484.0 1971-02-12 16.1926 16.2285 16.1329 16.2285 3.74289 382836.0 1971-02-16 16.2285 16.4197 16.1926 16.3301 3.76631 684084.0 1971-02-17 16.2703 16.2703 16.0492 16.0851 3.70981 652704.0 1971-02-18 16.0851 16.1209 15.7385 15.7385 3.62988 822156.0 ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ 2023-03-02 128.39 129.22 127.71 128.93 128.93 3.3401e6 2023-03-03 129.35 129.91 128.77 129.64 129.64 2.8592e6 2023-03-06 129.64 130.86 129.59 130.19 130.19 3.1312e6 2023-03-07 130.28 130.42 128.19 128.25 128.25 3.5304e6 2023-03-08 128.48 128.74 127.55 128.05 128.05 2.7788e6 2023-03-09 128.3 128.53 125.98 126.16 126.16 5.4783e6 2023-03-10 126.12 127.29 125.13 125.45 125.45 5.9902e6 13122 rows omitted

Create TSFrame object for AAPL

Similarly, we can create a TSFrame object for the AAPL data.

julia> aapl_ts = TSFrame(MarketData.yahoo(:AAPL))10650×6 TSFrame with Date Index
 Index       Open        High        Low         Close       AdjClose    Volum ⋯
 Date        Float64     Float64     Float64     Float64     Float64     Float ⋯
────────────────────────────────────────────────────────────────────────────────
 1980-12-12    0.128348    0.128906    0.128348    0.128348    0.099722  4.690 ⋯
 1980-12-15    0.12221     0.12221     0.121652    0.121652    0.094519  1.758
 1980-12-16    0.113281    0.113281    0.112723    0.112723    0.087582  1.057
 1980-12-17    0.115513    0.116071    0.115513    0.115513    0.089749  8.644
 1980-12-18    0.118862    0.11942     0.118862    0.118862    0.092351  7.344 ⋯
 1980-12-19    0.126116    0.126674    0.126116    0.126116    0.097987  4.863
 1980-12-22    0.132254    0.132813    0.132254    0.132254    0.102756  3.736
 1980-12-23    0.137835    0.138393    0.137835    0.137835    0.107093  4.695
     ⋮           ⋮           ⋮           ⋮           ⋮           ⋮           ⋮ ⋱
 2023-03-02  144.38      146.71      143.9       145.91      145.91      5.223 ⋯
 2023-03-03  148.04      151.11      147.33      151.03      151.03      7.066
 2023-03-06  153.79      156.3       153.46      153.83      153.83      8.755
 2023-03-07  153.7       154.03      151.13      151.6       151.6       5.618
 2023-03-08  152.81      153.47      151.83      152.87      152.87      4.720 ⋯
 2023-03-09  153.56      154.54      150.23      150.59      150.59      5.383
 2023-03-10  150.21      150.94      147.61      148.5       148.5       6.852
                                                 1 column and 10635 rows omitted

Create a 6-month subset of stock data

We would like to compare the stock returns for both the stocks for 6 months starting from June 1, 2021 till December 31, 2021. We use TSFrames.subset method to create new objects which contain the specified duration of data.

julia> date_from = Date(2021, 06, 01);
julia> date_to = Date(2021, 12, 31);
julia> ibm = TSFrames.subset(ibm_ts, date_from, date_to)150×6 TSFrame with Date Index Index Open High Low Close AdjClose Volume Date Float64 Float64 Float64 Float64 Float64 Float64 ───────────────────────────────────────────────────────────────────── 2021-06-01 138.623 139.417 137.428 137.849 126.576 2.5287e6 2021-06-02 138.26 139.34 137.772 139.312 127.919 2.9151e6 2021-06-03 138.537 139.465 137.706 139.149 127.77 4.32061e6 2021-06-04 139.579 141.061 139.35 140.937 129.411 3.26132e6 2021-06-07 141.061 142.199 140.698 141.511 129.938 3.62198e6 2021-06-08 141.606 143.595 141.606 142.514 130.86 5.31378e6 2021-06-09 142.476 144.426 142.275 144.044 132.264 5.54725e6 2021-06-10 144.809 146.119 143.174 143.92 132.15 4.97739e6 ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ 2021-12-22 129.06 129.79 127.6 129.75 122.119 3.9232e6 2021-12-23 130.0 130.96 129.52 130.63 122.947 3.649e6 2021-12-27 130.63 131.65 129.95 131.62 123.879 4.2939e6 2021-12-28 131.6 133.22 131.59 132.63 124.83 3.4452e6 2021-12-29 132.4 134.21 132.3 133.35 125.507 4.2399e6 2021-12-30 133.75 134.37 133.33 133.91 126.034 3.1581e6 2021-12-31 134.0 134.99 133.61 133.66 125.799 3.3621e6 135 rows omitted
julia> aapl = TSFrames.subset(aapl_ts, date_from, date_to)150×6 TSFrame with Date Index
 Index       Open     High     Low      Close    AdjClose  Volume
 Date        Float64  Float64  Float64  Float64  Float64   Float64
─────────────────────────────────────────────────────────────────────
 2021-06-01   125.08   125.35   123.94   124.28   123.01   6.76371e7
 2021-06-02   124.28   125.24   124.05   125.06   123.782  5.92789e7
 2021-06-03   124.68   124.85   123.13   123.54   122.278  7.62292e7
 2021-06-04   124.07   126.16   123.85   125.89   124.604  7.51693e7
 2021-06-07   126.17   126.32   124.83   125.9    124.614  7.10576e7
 2021-06-08   126.6    128.46   126.21   126.74   125.445  7.44038e7
 2021-06-09   127.21   127.75   126.52   127.13   125.831  5.68779e7
 2021-06-10   127.02   128.19   125.94   126.11   124.822  7.11864e7
     ⋮          ⋮        ⋮        ⋮        ⋮        ⋮          ⋮
 2021-12-22   173.04   175.86   172.15   175.64   174.36   9.21353e7
 2021-12-23   175.85   176.85   175.27   176.28   174.996  6.83566e7
 2021-12-27   177.09   180.42   177.07   180.33   179.016  7.49196e7
 2021-12-28   180.16   181.33   178.53   179.29   177.984  7.91443e7
 2021-12-29   179.33   180.63   178.14   179.38   178.073  6.23489e7
 2021-12-30   179.47   180.57   178.09   178.2    176.902  5.9773e7
 2021-12-31   178.09   179.23   177.26   177.57   176.276  6.40623e7
                                                     135 rows omitted

Combine adjusted closing prices of both stocks into one object

We now join (cbind) both the stocks' data into a single object for further analysis. We use TSFrames.join to create two columns containing adjusted closing prices of both the stocks. The join happens by comparing the Index values (dates) of the two objects. The resulting object contains two columns with exactly the same dates for which both the objects have data, all the other rows are omitted from the result.

julia> ibm_aapl = TSFrames.join(ibm[:, ["AdjClose"]], aapl[:, ["AdjClose"]]; jointype=:JoinBoth)150×2 TSFrame with Date Index
 Index       AdjClose  AdjClose_1
 Date        Float64   Float64
──────────────────────────────────
 2021-06-01   126.576     123.01
 2021-06-02   127.919     123.782
 2021-06-03   127.77      122.278
 2021-06-04   129.411     124.604
 2021-06-07   129.938     124.614
 2021-06-08   130.86      125.445
 2021-06-09   132.264     125.831
 2021-06-10   132.15      124.822
     ⋮          ⋮          ⋮
 2021-12-22   122.119     174.36
 2021-12-23   122.947     174.996
 2021-12-27   123.879     179.016
 2021-12-28   124.83      177.984
 2021-12-29   125.507     178.073
 2021-12-30   126.034     176.902
 2021-12-31   125.799     176.276
                  135 rows omitted
julia> TSFrames.rename!(ibm_aapl, [:IBM, :AAPL])150×2 TSFrame with Date Index Index IBM AAPL Date Float64 Float64 ────────────────────────────── 2021-06-01 126.576 123.01 2021-06-02 127.919 123.782 2021-06-03 127.77 122.278 2021-06-04 129.411 124.604 2021-06-07 129.938 124.614 2021-06-08 130.86 125.445 2021-06-09 132.264 125.831 2021-06-10 132.15 124.822 ⋮ ⋮ ⋮ 2021-12-22 122.119 174.36 2021-12-23 122.947 174.996 2021-12-27 123.879 179.016 2021-12-28 124.83 177.984 2021-12-29 125.507 178.073 2021-12-30 126.034 176.902 2021-12-31 125.799 176.276 135 rows omitted

After the join operation the column names are modified because we merged two same-named columns (AdjClose) so we use TSFrames.rename!() method to rename the columns to easily remembered stock names.

Convert data into weekly frequency using last values

Here, we convert daily stock data into weekly frequency by taking the value with which the trading closed on the last day of the week as the week's price.

julia> ibm_aapl_weekly = to_weekly(ibm_aapl)31×2 TSFrame with Date Index
 Index       IBM      AAPL
 Date        Float64  Float64
──────────────────────────────
 2021-06-04  129.411  124.604
 2021-06-11  132.8    126.049
 2021-06-18  125.637  129.127
 2021-06-25  128.902  131.75
 2021-07-02  122.915  138.53
 2021-07-09  124.232  143.628
 2021-07-16  121.932  144.895
 2021-07-23  124.074  147.042
     ⋮          ⋮        ⋮
 2021-11-19  109.225  159.38
 2021-11-26  108.999  155.667
 2021-12-03  111.851  160.661
 2021-12-10  116.792  178.143
 2021-12-17  119.907  169.893
 2021-12-23  122.947  174.996
 2021-12-31  125.799  176.276
               16 rows omitted

Compute weekly returns using the familiar log and diff functions

julia> ibm_aapl_weekly_returns = diff(log.(ibm_aapl_weekly))31×2 TSFrame with Date Index
 Index       IBM_log           AAPL_log
 Date        Float64?          Float64?
────────────────────────────────────────────────
 2021-06-04  missing           missing
 2021-06-11        0.0258467         0.0115306
 2021-06-18       -0.0554489         0.0241274
 2021-06-25        0.0256601         0.0201092
 2021-07-02       -0.0475583         0.050181
 2021-07-09        0.0106559         0.0361353
 2021-07-16       -0.0186871         0.00878231
 2021-07-23        0.0174144         0.0147145
     ⋮              ⋮                 ⋮
 2021-11-19       -0.0247661         0.0680366
 2021-11-26       -0.00207027       -0.0235705
 2021-12-03        0.0258271         0.0315732
 2021-12-10        0.0432291         0.103289
 2021-12-17        0.0263246        -0.0474148
 2021-12-23        0.0250372         0.0295916
 2021-12-31        0.0229304         0.00729139
                                 16 rows omitted
julia> TSFrames.rename!(ibm_aapl_weekly_returns, [:IBM, :AAPL])31×2 TSFrame with Date Index Index IBM AAPL Date Float64? Float64? ──────────────────────────────────────────────── 2021-06-04 missing missing 2021-06-11 0.0258467 0.0115306 2021-06-18 -0.0554489 0.0241274 2021-06-25 0.0256601 0.0201092 2021-07-02 -0.0475583 0.050181 2021-07-09 0.0106559 0.0361353 2021-07-16 -0.0186871 0.00878231 2021-07-23 0.0174144 0.0147145 ⋮ ⋮ ⋮ 2021-11-19 -0.0247661 0.0680366 2021-11-26 -0.00207027 -0.0235705 2021-12-03 0.0258271 0.0315732 2021-12-10 0.0432291 0.103289 2021-12-17 0.0263246 -0.0474148 2021-12-23 0.0250372 0.0295916 2021-12-31 0.0229304 0.00729139 16 rows omitted

Compute standard deviation of weekly returns

Computing standard deviation is done using the std function from Statistics package. The skipmissing is used to skip missing values which may have been generated while computing log returns or were already present in the data.

julia> ibm_std = std(skipmissing(ibm_aapl_weekly_returns[:, :IBM]))0.03407927976075671
julia> aapl_std = std(skipmissing(ibm_aapl_weekly_returns[:, :AAPL]))0.030582287537208864

Scatter plot of AAPL and IBM

Here, we use the Plots package to create a scatter plot with IBM weekly returns on the x-axis and Apple weekly returns on the y-axis.

plot(ibm_aapl_weekly_returns[:, :AAPL],
    ibm_aapl_weekly_returns[:, :IBM],
    seriestype = :scatter;
    xlabel = "AAPL",
    ylabel = "IBM",
    legend = false)