WIP: Add Indicators.jl functionality with TSFrames#155
WIP: Add Indicators.jl functionality with TSFrames#155
Conversation
Codecov Report
@@ Coverage Diff @@
## main #155 +/- ##
==========================================
- Coverage 91.41% 90.97% -0.45%
==========================================
Files 20 21 +1
Lines 431 432 +1
==========================================
- Hits 394 393 -1
- Misses 37 39 +2
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
|
Should we make this a package extension and use Requires.jl for Julia < 1.9, to avoid adding another dependency? |
Sure. im not too familiar with how package extensions will work in Julia, but there is blog post here. |
src/indicators.jl
Outdated
| runmean(X::TSFrame, x::Symbol; args...) = TSFrame(Indicators.runmean(X[:,x]; args...)) | ||
| sma(X::TSFrame, x::Symbol; args...) = TSFrame(Indicators.sma(X[:,x]; args...)) No newline at end of file |
There was a problem hiding this comment.
| runmean(X::TSFrame, x::Symbol; args...) = TSFrame(Indicators.runmean(X[:,x]; args...)) | |
| sma(X::TSFrame, x::Symbol; args...) = TSFrame(Indicators.sma(X[:,x]; args...)) | |
| Indicators.runmean(X::TSFrame, x::Symbol; kwargs...) = TSFrame(Indicators.runmean(X[:,x]; kwargs...)) | |
| Indicators.sma(X::TSFrame, x::Symbol; kwargs...) = TSFrame(Indicators.sma(X[:,x]; kwargs...)) |
Probably better to be explicit when adding a method like this, things become easier to interpret. Also, conventionally keyword arguments are splatted into kwargs... (not a major thing, but is easier to read).
Also, should this somehow preserve the index of ts?
There was a problem hiding this comment.
I see what you meant by preserving the index of ts?
julia> sp500_2y = TSFrames.subset(sp500, date_from, date_to)
505×6 TSFrame with Date Index
Index Open High Low Close AdjClose Volume
Date Float64 Float64 Float64 Float64 Float64 Float64
─────────────────────────────────────────────────────────────────────
2021-03-01 3842.51 3914.5 3842.51 3901.82 3901.82 5.11482e9
2021-03-02 3903.64 3906.41 3868.57 3870.29 3870.29 5.53601e9
2021-03-03 3863.99 3874.47 3818.86 3819.72 3819.72 6.17366e9
2021-03-04 3818.53 3843.67 3723.34 3768.47 3768.47 7.1954e9
2021-03-05 3793.58 3851.69 3730.19 3841.94 3841.94 6.85107e9
⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮
2023-02-23 4018.6 4028.3 3969.19 4012.32 4012.32 3.95294e9
2023-02-24 3973.24 3978.25 3943.08 3970.04 3970.04 3.8777e9
2023-02-27 3992.36 4018.05 3973.55 3982.24 3982.24 3.83695e9
2023-02-28 3977.19 3997.5 3968.98 3970.15 3970.15 5.0434e9
2023-03-01 3963.34 3971.73 3939.05 3951.39 3951.39 4.24948e9
495 rows omitted
...
...
julia> using Indicators
julia> sma(sp500_2y, :AdjClose)
505×1 TSFrame with Int64 Index
Index x1
Int64 Float64
────────────────
1 NaN
2 NaN
3 NaN
4 NaN
5 NaN
⋮ ⋮
501 4076.32
502 4065.17
503 4054.35
504 4037.64
505 4019.16
495 rows omittedShould index of "Date" remain preserved? I think for most Technical Indicators it makes some to preserve.
But there could also be some where the Timestamp is not meaningful. Also there is "burn in" for n number of observations in rolling statistics and trading indicators.
I'll proceed backwards from a TDD paradigm, dev and test and will see works
Co-authored-by: Anshul Singhvi <anshulsinghvi@gmail.com>
Project.toml
Outdated
| [deps] | ||
| DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" | ||
| Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" | ||
| Indicators = "70c4c096-89a6-5ec6-8236-da8aa3bd86fd" |
ext/IndicatorsExt.jl
Outdated
|
|
||
| # Methods for porting Indicators.jl functions to TSFrame objects from TSFrames.jl package | ||
| # See their respective documentation on Indicators.jl | ||
| Indicators.runmean(X::TSFrame, x::Symbol; kwargs...) = TSFrame(Indicators.runmean(X[:, x]; kwargs...), X[:, :Index]) |
There was a problem hiding this comment.
Preserving Index. Is there better way to integrate to TSFrame? More optimised way to avoid extra Construction operations?
ext/IndicatorsExt.jl
Outdated
| Indicators.kama(X::TSFrame, x::Symbol; kwargs...) = TSFrame(Indicators.kama(X[:, x]; kwargs...), X[:, :Index]) | ||
| Indicators.alma(X::TSFrame, x::Symbol; kwargs...) = TSFrame(Indicators.alma(X[:, x]; kwargs...), X[:, :Index]) | ||
| Indicators.zlema(X::TSFrame, x::Symbol; kwargs...) = TSFrame(Indicators.zlema(X[:, x]; kwargs...), X[:, :Index]) | ||
| # VWMA is defined on Matrix, not Array |
There was a problem hiding this comment.
Still thinking how to adapt methods that work on AbstractMatrix, not Array
| module TSFrames | ||
|
|
||
| using DataFrames, Dates, ShiftedArrays, RecipesBase, RollingFunctions, Tables | ||
| using DataFrames, Dates, ShiftedArrays, RecipesBase, RollingFunctions, Tables # , Indicators |
| include("vcat.jl") | ||
| include("broadcasting.jl") | ||
| include("tables.jl") | ||
| # include("indicators.jl") |
| date_from = Date(2021, 03, 1) | ||
| date_to = Date(2023, 03, 1) | ||
| sp500_2y = TSFrames.subset(sp500, date_from, date_to) | ||
| @test sma(sp500_2y, :AdjClose) |> typeof == TSFrame |
There was a problem hiding this comment.
make tests more diverse and meaningful, by using kwargs from upstream method
Been looking to use methods defined in Indicators.jl with TSFrame objects. Since Indicators.jl defines its methods using simple
AbstractArrayandMatrixtypes, it is relatively easy to integrate the two packages.I tried integrating the
runmeanandsma(simple moving average) method with TSFrames, and its relatively easy to integrate. It will be great to have those moving average and momentum based operations working out of box with TSFrames.