Repository: joshuaulrich/TTR Branch: master Commit: 76e5618e4a71 Files: 132 Total size: 403.1 KB Directory structure: gitextract_yqsyaveo/ ├── .Rbuildignore ├── .github/ │ ├── FUNDING.yml │ ├── issue_template.md │ ├── pull_request_template.md │ ├── security.md │ └── workflows/ │ └── ci.yaml ├── .gitignore ├── DESCRIPTION ├── LICENSE ├── Makefile ├── NAMESPACE ├── NEWS.md ├── R/ │ ├── ADX.R │ ├── ATR.R │ ├── CCI.R │ ├── CLV.R │ ├── CMF.R │ ├── CMO.R │ ├── CTI.R │ ├── DPO.R │ ├── DVI.R │ ├── DonchianChannel.R │ ├── EMV.R │ ├── GMMA.R │ ├── KST.R │ ├── MACD.R │ ├── MFI.R │ ├── MovingAverages.R │ ├── OBV.R │ ├── RSI.R │ ├── SAR.R │ ├── SNR.R │ ├── TDI.R │ ├── TRIX.R │ ├── TTR-package.R │ ├── TTRtools.R │ ├── VHF.R │ ├── WPR.R │ ├── WebData.R │ ├── ZigZag.R │ ├── adjRatios.R │ ├── aroon.R │ ├── bollingerBands.R │ ├── chaikinAD.R │ ├── chaikinVolatility.R │ ├── changes.R │ ├── keltnerChannels.R │ ├── percentRank.R │ ├── pivots.R │ ├── priceBands.R │ ├── rollFun.R │ ├── runFun.R │ ├── stochastics.R │ ├── ultimateOscillator.R │ ├── volatility.R │ ├── williamsAD.R │ └── zzz.R ├── README.md ├── THANKS ├── data/ │ └── ttrc.rda ├── inst/ │ └── tinytest/ │ ├── output/ │ │ ├── misc.rda │ │ ├── moving-averages.rda │ │ ├── oscillators.rda │ │ ├── overlays.rda │ │ ├── running-functions.rda │ │ ├── trend.rda │ │ ├── volatility.rda │ │ └── volume.rda │ ├── test-dvi.R │ ├── test-misc.R │ ├── test-moving-averages.R │ ├── test-oscillators.R │ ├── test-overlays.R │ ├── test-runfun.R │ ├── test-trend.R │ ├── test-volatility.R │ └── test-volume.R ├── man/ │ ├── ADX.Rd │ ├── ATR.Rd │ ├── CCI.Rd │ ├── CLV.Rd │ ├── CMF.Rd │ ├── CMO.Rd │ ├── CTI.Rd │ ├── DPO.Rd │ ├── DVI.Rd │ ├── DonchianChannel.Rd │ ├── EMV.Rd │ ├── GMMA.Rd │ ├── KST.Rd │ ├── MACD.Rd │ ├── MFI.Rd │ ├── MovingAverages.Rd │ ├── OBV.Rd │ ├── RSI.Rd │ ├── SAR.Rd │ ├── SNR.Rd │ ├── TDI.Rd │ ├── TRIX.Rd │ ├── TTR.Rd │ ├── TTRtools.Rd │ ├── VHF.Rd │ ├── WPR.Rd │ ├── WebData.Rd │ ├── ZigZag.Rd │ ├── adjRatios.Rd │ ├── aroon.Rd │ ├── bollingerBands.Rd │ ├── chaikinAD.Rd │ ├── chaikinVolatility.Rd │ ├── changes.Rd │ ├── keltnerChannels.Rd │ ├── priceBands.Rd │ ├── rollFun.Rd │ ├── runFun.Rd │ ├── runPercentRank.Rd │ ├── stochastics.Rd │ ├── ttrc.Rd │ ├── ultimateOscillator.Rd │ ├── volatility.Rd │ └── williamsAD.Rd ├── src/ │ ├── adjRatios.c │ ├── aroon.c │ ├── init.c │ ├── moving_averages.c │ ├── percent_rank.c │ ├── runfun.c │ ├── sar.c │ ├── ttr.h │ ├── wilderSum.c │ └── zigzag.c └── tests/ └── tinytest.R ================================================ FILE CONTENTS ================================================ ================================================ FILE: .Rbuildignore ================================================ R/pivots.R LICENSE WISHLIST ^.*\.Rproj$ ^\.Rproj\.user$ \.git \.gitignore ^.*\.orig$ ^.*\.sw. .travis.yml ^0.*\.patch$ ^.*\.tar.gz$ Makefile ================================================ FILE: .github/FUNDING.yml ================================================ github: [joshuaulrich] ================================================ FILE: .github/issue_template.md ================================================ ### Description [Describe the issue] ### Expected behavior [Describe the behavior/output you expected] ### Minimal, reproducible example ```r [Insert sample data and code] ``` ### Session Info ```r [Insert your sessionInfo() output] ``` ================================================ FILE: .github/pull_request_template.md ================================================ Please review the [contributing guide](CONTRIBUTING.md) before submitting your pull request. Please pay special attention to the [pull request](CONTRIBUTING.md#want-to-submit-a-pull-request) and [commit message](CONTRIBUTING.md#commit-messages) sections. Thanks for your contribution and interest in the project! ================================================ FILE: .github/security.md ================================================ # Security Policy ## Supported Versions As with most R packages, only the latest package version is supported with bug fixes, features, etc. This also applies to security updates. ## Reporting a Vulnerability To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. ================================================ FILE: .github/workflows/ci.yaml ================================================ # Run CI for R using https://eddelbuettel.github.io/r-ci/ name: ci on: push: pull_request: env: USE_BSPM: "true" _R_CHECK_FORCE_SUGGESTS_: "false" _R_CHECK_CRAN_INCOMING_ : "false" _R_S3_METHOD_LOOKUP_BASEENV_AFTER_GLOBALENV_: "true" _R_CHECK_CODETOOLS_PROFILE_: "suppressLocalUnused=false" _R_CHECK_LENGTH_1_CONDITION_: "true" _R_CHECK_LENGTH_1_LOGIC2_: "true" _R_CHECK_UNDOC_USE_ALL_NAMES_: "true" jobs: build: strategy: matrix: config: #- {os: macOS-latest} - {os: ubuntu-latest} runs-on: ${{ matrix.config.os }} steps: - uses: actions/checkout@v3 - name: Bootstrap run: | curl -OLs https://eddelbuettel.github.io/r-ci/run.sh chmod 0755 run.sh ./run.sh bootstrap - name: Dependencies run: ./run.sh install_all - name: Test run: ./run.sh run_tests ================================================ FILE: .gitignore ================================================ # History and data files .Rhistory .Rapp.history .RData # RStudio files .Rproj.user/ # produced vignettes vignettes/*.html vignettes/*.pdf # knitr and R markdown /*_cache/ /cache/ *.utf8.md *.knit.md # object and shared objects *.o *.so # vim *.swp *.swo *~ # R package build/check *.tar.gz *.Rcheck/ # miscellaneous 0*.patch *.bak *.orig ================================================ FILE: DESCRIPTION ================================================ Package: TTR Type: Package Title: Technical Trading Rules Version: 0.24.4.1 Authors@R: c( person(given="Joshua", family="Ulrich", role=c("cre","aut"), email="josh.m.ulrich@gmail.com"), person(given=c("Ethan","B."), family="Smith", role="ctb") ) Imports: xts (>= 0.10-0), zoo, curl LinkingTo: xts Enhances: quantmod Suggests: tinytest Description: A collection of over 50 technical indicators for creating technical trading rules. The package also provides fast implementations of common rolling-window functions, and several volatility calculations. License: GPL (>= 2) URL: https://github.com/joshuaulrich/TTR BugReports: https://github.com/joshuaulrich/TTR/issues ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: Makefile ================================================ #https://stackoverflow.com/questions/34603415/makefile-automatic-target-generation #https://www.gnu.org/software/make/manual/make.html#Static-Pattern #https://stackoverflow.com/questions/2826029/passing-additional-variables-from-command-line-to-make #https://stackoverflow.com/questions/2214575/passing-arguments-to-make-run R_HOME = /usr PKG_PATH = ${PWD} TOP = ${PWD}/.. PKG_DESC = ${PKG_PATH}/DESCRIPTION PKG_NAME = $(shell sed -ne "s/^Package: //p" ${PKG_DESC} | tr -d '\n') PKG_VER = $(shell sed -ne "s/^Version: \(.*\)/\1/p" ${PKG_DESC} | tr -d '\n') PKG_TARGZ = $(PKG_NAME)_$(PKG_VER).tar.gz PKG_BUILD_OPTS ?= --no-build-vignettes R_LIB ?= $(shell Rscript -e 'cat(.libPaths()[1L])') PKG_INST_FILE = $(R_LIB)/${PKG_NAME}/DESCRIPTION PKG_R_FILES := $(wildcard ${PKG_PATH}/R/*.R) PKG_RD_FILES := $(wildcard ${PKG_PATH}/man/*.Rd) PKG_SRC_FILES := $(wildcard ${PKG_PATH}/src/*) PKG_HEADER_FILES := $(wildcard ${PKG_PATH}/inst/include/*h) PKG_ALL_FILES := ${PKG_PATH}/DESCRIPTION ${PKG_PATH}/NAMESPACE ${PKG_HEADER_FILES} \ $(PKG_R_FILES) $(PKG_RD_FILES) $(PKG_SRC_FILES) ${PKG_PATH}/.Rbuildignore HTML_FILES := $(patsubst %.Rmd, %.html, $(wildcard *.Rmd)) \ $(patsubst %.md, %.html, $(wildcard *.md)) UNIT_TEST_SUITE = ${PKG_PATH}/tests/tinytest.R UNIT_TEST_FILES = $(wildcard ${PKG_PATH}/inst/tinytest/test-*.R) BENCHMARK_FILE = ${PKG_PATH}/inst/benchmarks/benchmark.subset.R .PHONY: docs build install check tests test clean all: cran #man/*.Rd depend on R/*.R files print: @echo 'path: $(PKG_PATH) \ inst_file: $(PKG_INST_FILE) \ tar.gz: $(PKG_TARGZ)' # Build package build: $(PKG_TARGZ) $(PKG_TARGZ): $(PKG_ALL_FILES) $(UNIT_TEST_FILES) $(UNIT_TEST_SUITE) @${R_HOME}/bin/R CMD build ${PKG_BUILD_OPTS} ${PKG_PATH} --no-build-vignettes # Install package install: build $(PKG_INST_FILE) $(PKG_INST_FILE): $(PKG_TARGZ) @${R_HOME}/bin/R CMD INSTALL ${PKG_TARGZ} --no-byte-compile # Run R CMD check check: docs build @_R_CHECK_CRAN_INCOMING_=false \ _PKG_TINYTEST_VERBOSE_=1 _PKG_TINYTEST_COLOR_=FALSE \ ${R_HOME}/bin/R CMD check ${PKG_TARGZ} --no-vignettes docs: ${PKG_R_FILES} @${R_HOME}/bin/Rscript -e "roxygen2::roxygenize(roclets='rd')" \ && sed -i '/^RoxygenNote/d' ${PKG_PATH}/DESCRIPTION \ && /bin/rm --force ${PKG_PATH}/src/*.o \ && /bin/rm --force ${PKG_PATH}/src/*.so # Check for CRAN cran: @${R_HOME}/bin/R CMD build ${PKG_PATH} && \ _PKG_TINYTEST_VERBOSE_=1 _PKG_TINYTEST_COLOR_=FALSE \ _R_CHECK_CRAN_INCOMING_=false ${R_HOME}/bin/R CMD check ${PKG_TARGZ} --as-cran # Run unit test suite tests: install ${UNIT_TEST_FILES} @_PKG_TINYTEST_VERBOSE_=2 _PKG_TINYTEST_COLOR_=TRUE \ ${R_HOME}/bin/Rscript ${UNIT_TEST_SUITE} html: $(HTML_FILES) %.html: %.Rmd R --slave -e "set.seed(100);rmarkdown::render('$<')" %.html: %.md R --slave -e "set.seed(100);rmarkdown::render('$<')" clean: /bin/rm --force $(HTML_FILES) ${PKG_PATH}/src/*.o ${PKG_PATH}/src/*.so ================================================ FILE: NAMESPACE ================================================ export(ADX) export(ALMA) export(ATR) export(BBands) export(CCI) export(CLV) export(CMF) export(CMO) export(CTI) export(DEMA) export(DPO) export(DVI) export(DonchianChannel) export(EMA) export(EMV) export(EVWMA) export(GMMA) export(HMA) export(KST) export(MACD) export(MFI) export(OBV) export(PBands) export(ROC) export(RSI) export(SAR) export(SMA) export(SMI) export(SNR) export(TDI) export(TR) export(TRIX) export(VHF) export(VWAP) export(VWMA) export(WMA) export(WPR) export(ZLEMA) export(ZigZag) export(adjRatios) export(aroon) export(chaikinAD) export(chaikinVolatility) export(getYahooData) export(growth) export(keltnerChannels) export(lags) export(momentum) export(naCheck) export(rollSFM) export(runCor) export(runCov) export(runMAD) export(runMax) export(runMean) export(runMedian) export(runMin) export(runRange) export(runPercentRank) export(runSD) export(runSum) export(runVar) export(stoch) export(stockSymbols) export(ultimateOscillator) export(volatility) export(wilderSum) export(williamsAD) import(xts) import(zoo) importFrom(curl,curl_download) importFrom(curl,new_handle) importFrom(stats,approx) importFrom(stats,embed) importFrom(stats,na.omit) importFrom(stats,sd) importFrom(stats,cor) importFrom(utils,flush.console) importFrom(utils,read.csv) importFrom(utils,read.table) useDynLib(TTR, .registration = TRUE, .fixes = "C_") ================================================ FILE: NEWS.md ================================================ # Changes in 0.24.4 * Added Ethan B. Smith as a contributor. Thanks Ethan! ### NEW FEATURES - Added a `TR()` function to calculate the true high, true low, and true range. Refactored `ATR()` to use the `TR()` function. Thanks to @openbmsjsc and Steve Bronder for the reports, and Ethan B. Smith for the PR. (#18, #114, #124) ### BUG FIXES * Fix `stockSymbols()` for ticker "NA". `read.table()` converts the string "NA" to a missing value (NA) because `na.strings = "NA"` by default. This causes an issue because there's actually a company with "NA" for the ticker. (#128) - `CTI()` did not pad its result with leading NA when the input was not coerced to an xts object. This was different from other TTR functions (e.g. `SMA()`, `RSI()`, `ROC()`). (#127) - Removed the `VMA()` function, which was never correct because the results made no sense. - Check that the `wma()` C function has enough non-NA values and throw an error if it doesn't. This could cause the `WMA()` function to crash the user's R session. (#126) - `runMean(..., cumulative = TRUE)` didn't account for leading NA in the denominator. (#122) - `runSD(x, cumulative = TRUE)` returned all NA when `x` had any leading NA. Thanks to Ethan B. Smith for the report. (#121) - The `TRIX()` signal line did not use `nSig` unless `maType` was provided. Thanks to @SatoshiReport for the... report. (#120) ### MISCELLANEOUS - Use symbols for native routine entry points to make them explicit and unable to be found accidentally. (#123) # Changes in 0.24.3 ### SIGNIFICANT USER-VISIBLE CHANGES - Significant improvement to `ALMA()` calculation speed. Thanks to Ethan B. Smith for the report and suggested fix. (#117) ### NEW FEATURES - Added Keltner Channels. Thanks to Nick Procyk for the patch and docs (#106) ### BUG FIXES - `runPercentRank()` would segfault if `x` had fewer non-NA observations than the value for `n`. Thanks to Ian Fellows for the report. (#112) - `run*(x, n = 1, cumulative = TRUE)` functions would return NA for the first value. Thanks to Ethan B. Smith for the report and PR! (#111, #108, #88) - Fix NA check off-by-one error in `aroon()` that caused it to fail if there were exactly enough non-NA values. (#102) # Changes in 0.24.2 ### BUG FIXES - Check for `ratio > 0` before calculating `n` in `zlema()` C code. The prior code could result in division by 0, which was flagged by clang-UBSAN. Thanks to Prof Brian Ripley for the report. (#100) # Changes in 0.24.1 ### BUG FIXES - Fix leading NA accounting in `wma()` C code. The prior code caused invalid reads under valgrind. Thanks to Prof Brian Ripley for the report. (#99) - Check for `ratio > 0` before calculating `n` `n ema()` C code. The prior code could result in division by 0, which was flagged by UBSAN. Thanks to Prof Brian Ripley for the report. (#100) - Make `ALMA()` output length equal input length when the input can not be converted to xts. This was caused by the difference between `rollapply.default()` and `rollapply.xts()`. Thanks to GitHub user @marksimmonds for the report. (#29) - Fix `stoch()` in very rare cases where `fastK = Inf`. I could only reproduce this if the Close is > High and High and Low are equal, but that is a data error. I fixed anyway because there may be other cases I don't anticipate. Thanks to GitHub user @cjuncosa for the report. (#52) - Fix `MFI()` when money flow is always zero or positive. The denominator of the money ratio will be zero if there is no negative money flow for `n` consecutive observations (e.g. during a strong up-trend), which causes the money flow index to be Inf. Set the money flow index to 100 in this case. And the money ratio will be NaN if there's no money flow for `n` consecutive observations (e.g. if there are no trades), which causes the money flow index to be NaN. Set the money flow index to 50 in this case. Thanks to GitHub user @jgehw for the report, reproducible example, and suggested patch. (#81) # Changes in 0.24.0 ### SIGNIFICANT USER-VISIBLE CHANGES - Updated `stockSymbols()` to use the NASDAQ FTP site instead of downloading the CSV from the NASDAQ stock screener page. Some columns are no longer populated because they are not provided in the FTP file: LastSale ,MarketCap, IPOyear, Sector, Industry These columns will be removed in a future version. (#98, #5, #97) - `runPercentRank(x, n, cumulative = TRUE)` now sets observations in the initialization period to NA. This is consistent with the other running/rolling functions in TTR. If you want the previous behavior, you should use `runPercentRank(x, n = 1, cumulative = TRUE)`. Thanks to GitHub user @httassadar for the report. (#73) ### NEW FEATURES - Add Ehler's Correlation Trend Indicator. Thanks to Evelyn Mitchell for the suggestion, and for Ethan B. Smith for the initial implementation. (#92) ### BUG FIXES - `runMAD()` returned incorrect values when `cumulative = TRUE` and the input contained leading NA. Thanks to GitHub user @stellathecat for the report. This also affected `runMedian()`. (#93) - `ZLEMA()` would crash when `ratio = 0.0` and `n` was not specified. Thanks to GitHub user @yogat3ch for the report! (#95) - `WMA()` did not return an xts object when passed an xts object for `x` that had leading NA, with the default `wts = 1:n`. Thanks to Cory Fletcher for reporting this issue via email. (#96) - `stoch()` was wrong when `bounded = FALSE`. Thanks to GitHub user @rfinfun for the report and patch. (#74) - `HMA()` threw an error when `n` was an odd number. This was because the first call to `WMA()` used `n = n / 2` which caused `n` to not be an integer. Thanks to GitHub user @dragie for the report. (#76) # Changes in 0.23.0 ### SIGNIFICANT USER-VISIBLE CHANGES - Update `DVI()` to use `runPercentRank()`. Thanks to Ivan Popivanov for the patch. - `getYahooData()` now returns an xts object with Date index (not POSIXct). - Column names for moving average function outputs are no longer based on the input column names. ### NEW FEATURES - Add `HMA()` and `ALMA()` functions/docs. Thanks to Ivan Popivanov. - Add Ultimate Oscillator function/docs/tests. Thanks to Ivan Popivanov. ### BUG FIXES - `run*()` functions now error if there are not enough non-NA values. - Change all instances of `lag()` to `lag.xts()` in case `x` is a matrix. Thanks to Ivan Popivanov for the report. - Correct output column names in `ATR()` docs. - `CLV()` now sets NaN and Inf values to 0, instead of only NaN values. - Fix `OBV()` so `OBV[t] = OBV[t-1]` when `Close[t] == Close[t-1]`. - Fix dead links in documentation. # Changes in 0.22.0 ### SIGNIFICANT USER-VISIBLE CHANGES - `CCI()` now returns an object with column names ("cci"). - All moving average functions now attempt to set column names. - Added clarification on the displaced nature of `DPO()`. - `SAR()` now sets the initial gap based on the standard deviation of the high-low range instead of hard-coding it at 0.01. ### NEW FEATURES - Added `rollSFM()` function that calculates alpha, beta, and R-squared for a single-factor model. Thanks to James Toll for the prototype. - Added `runPercentRank()` function. Thanks to Charlie Friedemann. - Moved slowest portion of `aroon()` to C. - `DonchianChannel()` gains an `include.lag = FALSE` argument, which includes the current period's data in the calculation. Setting it to `TRUE` replicates the original calculation. Thanks to Garrett See and John Bollinger. - The Stochastic Oscillator and Williams' %R now return 0.5 (instead of NaN) when a securities' price doesn't change over a sufficient period. - All moving average functions gain `...`. - Users can now change alpha in Yang Zhang volatility calculation. ### BUG FIXES - Fixed `MACD()` when `maType` is a list. Now `mavg.slow = maType[[2]]` and `mavg.fast = maType[[1]]`, as users expected based on the order of the `nFast` and `nSlow` arguments. Thanks to Phani Nukala and Jonathan Roy. - Fixed bug in `lags()`. Thanks to Michael Weylandt. - Corrected error in Yang Zhang volatility calculation. Thanks to several people for identifying this error. - Correction to `SAR()` extreme point calculations. Thanks to Vamsi Galigutta. - `adjRatios()` now ensures all inputs are univariate. Thanks to Garrett See. - `EMA()` and `EVWMA()` now ensure `n` is less than the number of non-NA values. Thanks to Roger Bos. - Fix to `BBands()` docs. Thanks to Evelyn Mitchell. # Changes in 0.21.1 ### BUG FIXES - Fixed `stockSymbols()` for nasdaq.com changes (again), and attempted to make `stockSymbols()` more robust to nasdaq.com changes. - Corrected final calculation in Yang-Zhang volatility. Thanks to Shal Patel. - Corrected `k` in Yang-Zhang volatility. Thanks to Ian Rayner. - Corrected `s2o` and `s2c` in Yang-Zhang volatility. Thanks to Ian Rayner. - Corrected `KST()` when input is xts (result is now * 100). Thanks to Yuanwei. # Changes in 0.21.0 ### NEW FEATURES - Added variable moving average function, `VMA()`. - Added Brian Peterson's price bands function, `PBands()`. - Added David Varadi's `DVI()` indicator. - Added `wilder` and `ratio` arguments to `DEMA`. Thanks to Matthew Fornari for the suggestion. ### BUG FIXES - Changed `wilderSum()` to seed initial value with raw sum. This matches Wilder's original calculations. Thanks to Mahesh Bp for the report. - The `BBands()` standard deviation calculation now uses the population instead of sample statistic. This is consistent with Bollinger Band literature. Thanks to Jeff Ryan for the patch. - Fixed `stockSymbols()` for nasdaq.com changes. - Fixed `ZLEMA()` default ratio by changing it from `2/(n-1)` to `2/(n+1)`. This makes it consistent with `EMA()`. Thanks to Dirk Eddelbuettel. - Corrected close-to-close volatility. Thanks to James Toll for the report. - `adjRatios()` failed (spectacularly) if there were missing close prices. Thanks to Garrett See for the report. # Changes in 0.20.2 ### NEW FEATURES - Added `VWAP()` and `VWMA()`. Thanks to Brian Peterson. - Added v-factor generalization to `DEMA()`. Thanks to John Gavin. - Updated `volatility()` to handle univariate case of `calc = "close"`. Thanks to Cedrick Johnson. - Moved `EMA()`, `SAR()`, and `wilderSum ()`from .Fortran to `.Call ()`and used `xts:::naCheck()` instead of TTR's NA check mechanism. - `RSI ()`up/down momentum is now faster with xts. Thanks to Jeff Ryan. - If `ratio` is specified in `EMA ()`but `n` is missing, the traditional value of `n` is approximated and returned as the first non-NA value. ### BUG FIXES - Fix to `stoch()` when `maType` is a list and `n` is not set in the list's 3rd element. Thanks to Wind Me. - Fixed `fastK` in `stoch()` when `smooth != 1`. - Fixed segfault in `EMA ()`when `n < NROW(x)`. Thanks to Douglas Hobbs. - `test.EMA.wilder()` failed under R-devel. Thanks to Prof Brian Ripley. # Changes in 0.20.1 ### NEW FEATURES - Updated `CMO()`, `DPO()`, `DonchianChannel()`, `RSI()`, and `TDI ()` to *explicitly* use xts internally. ### BUG FIXES - Fixed bug in `WMA()`, `EVWMA()`, `ZLEMA()`, and `GMMA()`; results were not being `reclass()`ed back to their original class. - Set column names after `cbind ()` call in the following functions: - `ADX()` - `aroon()` - `ATR()` - `BBands()` - `DonchianChannel()` - `EMV()` - `KST()` - `MACD()` - `stoch()` - `SMI()` - `TDI()` - `TRIX()` - Fixed bug in `VHF()`; missing `abs()` calculation in the denominator. Thanks to Jürgen Wurzer for the report! # Changes in 0.20.0 - Fixed version number; 0.20-0 is now > 0.14-0 (rookie mistake). ### SIGNIFICANT USER-VISIBLE CHANGES - `getYahooData()` now returns an xts object. - Added column names to output for `ADX()`, `EMV()`, and `CLV ()` (for xts). - `momentum()` in `CMO()` no longer sets `na = 100`. - Replaced `na` argument in `momentum()` and `ROC()` with `na.pad`. - Moved `maType` argument default values from function formals to function body for the following functions: - `ADX()` - `ATR()` - `CCI()` - `DPO()` - `EMV()` - `KST()` - `MACD()` - `RSI()` - `TRIX()` - `BBands()` - `chaikinVolatility()` - `stoch()` - `SMI()` ### NEW FEATURES - `adjRatios()` creates split and/or dividend adjustment ratio series via C code. - `GMMA()` calculates the Guppy Multiple Moving Average. - `volatility()` now has Yang Zhang, and Garman-Klass (Yang Zhang) calculations. - The functions below now have cumulative argument. This allows the calculation of "from inception" running series. - `runSum()`, `runMin()`, `runMax()` - `runMean()`, `runMedian()` - `runCov()`, `runCor()`, `runVar()`, `runSD()`, `runMAD()` - Added internal smoothing to `FastK` in `stoch()` via `smooth` argument. Thanks to Stanley Neo. - `getYahooData()` now uses `adjRatios(),` which yields significant speed improvements for larger data sets. - All functions now use xts internally, adding support for all major time series classes. If `try.xts()` fails on the input object(s), they will be converted to a matrix and a matrix object will be returned. - Added `bounded` arg to `stoch()` and `SMI()`, which includes the current period in the calculation. - Added the zig zag indicator: `ZigZag()`. - Added volatility estimators/indicators: `volatility()`, with the following calculations: - Close-to-Close - Garman Klass - Parkinson - Rogers Satchell - Added Money Flow Index: `MFI()`. - Added Donchian channel: `DonchianChannel()`. - Added `multiple` argument to `TDI()`, allowing more user control. - Added `naCheck()` and implemented it in the moving average functions. ### BUG FIXES - Fixed bug when `maType` was a list and `n` was not specified in `maType`. This affected: `stoch()`, `SMI()`, `RSI()`, `KST()`, `MACD()`, `TRIX()`. - Corrected NaN replacement in `CLV()`. - Corrected `williamsAD()`: the result is 0 if C(t) = C(t-1). - Corrected `runMedian()` and `runMAD()`. The argument controlling which type of median to calculate for even-numbered samples wasn't being passed to the Fortran routine. - `aroon()` calculation starts at period `n+1`, instead of `n`. - Added NA to first element of `closeLag` of `ATR()`. - Corrected `BBands()` and `CCI()` for `rowMeans()` use on xts objects. - Made changes to Rd files to pass R CMD check on R-devel (2.9.0). # Changes in 0.14.0 ### SIGNIFICANT USER-VISIBLE CHANGES - Changed default `type` of `ROC()` to `continuous`. - Changed `BBands()` %B output value from `pct.b` to `pctB`. - Changed `WPR()` output value from `pct.R` to `pctR`. - Changed `WPR()` MA output value from `ma.emv` to `emvMA`. - Changed `aroon()` output values from `aroon.xx` to `aroonXx`. - Renamed: - `chaikinMF()` to `CMF()` - `stochastic()` to `stoch()` - `bollingerBands()` to `BBands()` - Set `na = NA` for `momentum()` and `ROC()` functions in files KST.R, RSI.R, and TDI.R, and changed `ROC()` to use `type = "discrete"` in chaikinVolatility.R. - Made the following changes to the `ZLEMA()` function: - Add `ratio = NULL` argument. - Non-integer lags are a weighted mean of the two nearest observations, based on their proximity to the lag value. - Change 'lag = ratio^(-1)' to fully support `ratio` argument. - Changed the `BBands()` function's `sd` argument from a list that allows other dispersion functions to simply indicate the number of standard deviations to use. ### NEW FEATURES - Changed `maType` arguments and updated documentation for: - `RSIm()` - `ADX()` - `ATR()` - `CCI()` - `DPO()` - `EMV()` - `RSI()` - `BBands()` - `chaikinVolatility()` - `stoch()` - `SMI()` - `TRIX()` - `MACD()` - `KST()` - Added Stochastic Momentum Index `SMI()` and `williamsAD()` functions and documentation. - Added Fortran implementations of - `SMA()` - `EMA()` - `WMA()` - `EVWMA()` - `ZLEMA()` - `PSAR()` - Added NA checking/handling for many functions. - Added `ratio = NULL` argument to `EMA()`. - Changed all usage of `roll*()` to their respective Fortran implementations and removed the `rollFun()` function. Added Fortran based functions are: - `runSum()` - `wilderSum()` - `runMin()` - `runMax()` - `runMean()` - `runCov()` - `runCor()` - `runVar()` - `runSD()` - `runMedian()` - `runMAD()` - Changed `CCI()` to use `runMAD()` internally. ### DEPRECATED & DEFUNCT - Removed `oscillator()` function and transferred functionality to `MACD()` function. - Removed `chaikinOscillator()`, since it can be created via `MACD(chaikinAD(...))`. ### BUG FIXES - `match.arg(type)` in `ROC()` changed to simple subsetting of type. - Changed trailing zeros to trailing NAs in `DPO()`. - Fixed `WMA()` bug that allowed `x` and `wts` vectors to have different length if either series had leading NAs (similar to `EVWMA()` function). - Fixed `runCov()` bug that allowed `x` and `y` vectors to have different length if either series had leading NAs (similar to `EVWMA()` function). - Corrected `EVWMA()` to start at period `n` instead of `n-1`. - Removed `message` function from CCI.R, VHF.R, WPR.R, aroon.R bollingerBands.R, and stochastics.R. # Changes in 0.13.2 ### SIGNIFICANT USER-VISIBLE CHANGES - Changed order of `oscillator()` arguments from `ma.slow`, `ma.fast`, `ma.sig` to the traditional `ma.fast`, `ma.slow`, `ma.sig`. Thanks to Jeff Ryan. - The arguments to the `chaikinOscillator()` function were changed as above. - Changed `EVWMA()` so period `n` contains the value for periods `(i-n+1):n` and so periods `1:(n-2)` will be NA. - Changed `EMA()` so periods `1:n` will be NA. # Changes in 0.13.1 ### SIGNIFICANT USER-VISIBLE CHANGES - Changed `bbands()` to `bollingerBands()`. - Changed `DX()` to `ADX()`. - Changed `stoch()` to `stochastic()`. ### BUG FIXES - Corrected mis-spellings in documentation. ================================================ FILE: R/ADX.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Welles Wilder's Directional Movement Index #' #' Directional Movement Index; developed by J. Welles Wilder. #' #' The \code{DIp}/\code{DIn} (positive/negative) is the percentage of the true #' range that is up/down. #' #' @aliases ADX DI DX #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. #' @param n Number of periods to use for DX calculation (not ADX calculation). #' @param maType A function or a string naming the function to be called. #' @param \dots Other arguments to be passed to the \code{maType} function. #' @return A object of the same class as \code{HLC} or a matrix (if #' \code{try.xts} fails) containing the columns: #' \describe{ #' \item{ DIp }{ The positive Direction Index. } #' \item{ DIn }{ The negative Direction Index. } #' \item{ DX }{ The Direction Index. } #' \item{ ADX }{ The Average Direction Index (trend strength). } #' } #' @note A buy/sell signal is generated when the +/-DI crosses up over the #' -/+DI, when the DX/ADX signals a strong trend. A high/low DX signals a #' strong/weak trend. DX is usually smoothed with a moving average (i.e. the #' ADX). #' @author Joshua Ulrich #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. The DX calculation uses #' \code{\link{ATR}}. See \code{\link{aroon}}, \code{\link{CCI}}, #' \code{\link{TDI}}, \code{\link{VHF}}, \code{\link{GMMA}} for other indicators #' that measure trend direction/strength. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.fmlabs.com/reference/DI.htm}\cr #' \url{https://www.fmlabs.com/reference/DX.htm}\cr #' \url{https://www.fmlabs.com/reference/ADX.htm}\cr #' \url{https://www.fmlabs.com/reference/ADXR.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=49}\cr #' \url{https://www.linnsoft.com/techind/directional-indicator-diplus-diminus}\cr #' \url{https://www.linnsoft.com/techind/adx-avg-directional-movement}\cr #' \url{https://www.linnsoft.com/techind/adxr-avg-directional-movement-rating}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:average_directional_index_adx}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' dmi.adx <- ADX(ttrc[,c("High","Low","Close")]) #' "ADX" <- function(HLC, n=14, maType, ...) { # Welles Wilder's Directional Movement Index HLC <- try.xts(HLC, error=as.matrix) dH <- momentum(HLC[,1]) dL <- -momentum(HLC[,2]) DMIp <- ifelse( dH==dL | (dH< 0 & dL< 0), 0, ifelse( dH >dL, dH, 0 ) ) DMIn <- ifelse( dH==dL | (dH< 0 & dL< 0), 0, ifelse( dH . # #' True Range / Average True Range #' #' True range (TR) is a measure of volatility of a High-Low-Close series; #' average true range (ATR) is a Welles Wilder's style moving average of the TR. #' Developed by J. Welles Wilder in 1978. #' #' TR incorporates yesterday's close in the calculation (high minus low). E.g. #' if yesterday's close was higher than today's high, then the TR would equal #' yesterday's close minus today's low. #' #' The ATR is a component of the Welles Wilder Directional Movement Index #' (\code{DX}, \code{ADX}). #' #' @aliases ATR TR #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. #' @param n Number of periods for moving average. #' @param maType A function or a string naming the function to be called. #' @param \dots Other arguments to be passed to the \code{maType} function. #' @return A object of the same class as \code{HLC} or a matrix (if #' \code{try.xts} fails) containing the columns: #' \describe{ #' \item{ tr }{ The true range of the series. } #' \item{ atr }{ The average (as specified by \code{ma}) true range of the series. } #' \item{ trueHigh }{ The true high of the series. } #' \item{ trueLow }{ The true low of the series. } #' } #' @author Joshua Ulrich #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. See \code{\link{DX}}, which uses true #' range. See \code{\link{chaikinVolatility}} for another volatility measure. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.fmlabs.com/reference/TR.htm}\cr #' \url{https://www.fmlabs.com/reference/ATR.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=35}\cr #' \url{https://www.linnsoft.com/techind/true-range-tr}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:average_true_range_atr}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' tr <- TR(ttrc[,c("High","Low","Close")]) #' atr <- ATR(ttrc[,c("High","Low","Close")], n=14) #' #' @rdname ATR "TR" <- function(HLC) { # True Range HLC <- try.xts(HLC, error=as.matrix) if(is.xts(HLC)) { closeLag <- lag.xts(HLC[,3]) } else { closeLag <- c( NA, HLC[-NROW(HLC),3] ) } trueHigh <- pmax( HLC[,1], closeLag, na.rm=FALSE ) trueLow <- pmin( HLC[,2], closeLag, na.rm=FALSE ) tr <- trueHigh - trueLow result <- cbind(tr, trueHigh, trueLow ) colnames(result) <- c('tr','trueHigh','trueLow') reclass( result, HLC ) } #' @rdname ATR "ATR" <- function(HLC, n=14, maType, ...) { # Average True Range / True Range HLC <- try.xts(HLC, error=as.matrix) tr <- TR(HLC) maArgs <- list(n=n, ...) # Default Welles Wilder EMA if(missing(maType)) { maType <- 'EMA' if(is.null(maArgs$wilder)) { # do not overwrite user-provided value maArgs$wilder <- TRUE } } atr <- do.call( maType, c( list(tr[,1]), maArgs ) ) result <- cbind( tr[,1], atr, tr[,2:3]) colnames(result) <- c('tr','atr','trueHigh','trueLow') reclass( result, HLC ) } ================================================ FILE: R/CCI.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Commodity Channel Index #' #' The Commodity Channel Index (CCI) attempts to identify starting and ending #' trends. #' #' CCI relates the current price and the average of price over \code{n} periods. #' The CCI usually falls in a channel of -100 to 100. A basic CCI trading system #' is: Buy (sell) if CCI rises above 100 (falls below -100) and sell (buy) when #' it falls below 100 (rises above -100). #' #' CCI is usually calculated using the typical price, but if a univariate series #' (e.g. Close, Weighted Close, Median Price, etc.) is provided, it will be used #' instead. #' #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. If only a univariate series is given, it will be #' used. See details. #' @param n Number of periods for moving average. #' @param maType A function or a string naming the function to be called. #' @param c Constant to apply to the mean deviation. #' @param \dots Other arguments to be passed to the \code{maType} function. #' @return A object of the same class as \code{HLC} or a vector (if #' \code{try.xts} fails) containing the CCI values. #' @note If \code{HLC} is a High-Low-Close matrix, then typical price will be #' calculated. If \code{HLC} is a vector, then those values will be used #' instead of the typical price. #' @author Joshua Ulrich #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. See \code{\link{aroon}}, #' \code{\link{ADX}}, \code{\link{TDI}}, \code{\link{VHF}}, \code{\link{GMMA}} #' for other indicators that measure trend direction/strength. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.fmlabs.com/reference/CCI.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=42}\cr #' \url{https://www.linnsoft.com/techind/cci-commodity-channel-index}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:commodity_channel_index_cci}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' cci <- CCI(ttrc[,c("High","Low","Close")]) #' "CCI" <- function(HLC, n=20, maType, c=0.015, ...) { # Commodity Channel Index HLC <- try.xts(HLC, error=as.matrix) if(NCOL(HLC)==3) { if(is.xts(HLC)) { xa <- xcoredata(HLC) HLC <- xts(apply(HLC, 1, mean),index(HLC)) xcoredata(HLC) <- xa } else { HLC <- apply(HLC, 1, mean) } } else if(NCOL(HLC)!=1) { stop("Price series must be either High-Low-Close, or Close/univariate.") } maArgs <- list(n=n, ...) # Default MA if(missing(maType)) { maType <- 'SMA' } mavg <- do.call( maType, c( list(HLC), maArgs ) ) meanDev <- runMAD( HLC, n, center=mavg, stat="mean" ) cci <- ( HLC - mavg ) / ( c * meanDev ) if(is.xts(cci)) { colnames(cci) <- "cci" } reclass(cci, HLC) } ================================================ FILE: R/CLV.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Close Location Value #' #' The Close Location Value (CLV) relates the day's close to its trading range. #' #' The CLV will fall in a range of -1 to +1. If the CLV is +/-1, the close is #' at the high/low; if the CLV is 0, the close is directly between the high and #' low. #' #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. #' @return A object of the same class as \code{HLC} or a vector (if #' \code{try.xts} fails) containing the Close Location Values of a #' High-Low-Close price series. #' @author Joshua Ulrich #' @seealso See \code{\link{chaikinAD}}, which uses CLV. #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' clv <- CLV(ttrc[,c("High","Low","Close")]) #' "CLV" <- function(HLC) { # Close Location Value HLC <- try.xts(HLC, error=as.matrix) clv <- ((HLC[,3]-HLC[,2]) - (HLC[,1]-HLC[,3])) / (HLC[,1]-HLC[,2]) # Account for H=L=C clv[is.nan(clv) | is.infinite(clv)] <- 0 if(is.xts(clv)) colnames(clv) <- 'clv' reclass( clv, HLC ) } ================================================ FILE: R/CMF.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Chaikin Money Flow #' #' Chaikin Money Flow compares total volume over the last \code{n} time periods #' to total volume times the Close Location Value (CLV) over the last \code{n} #' time periods. Developed by Marc Chaikin. #' #' Chaikin Money Flow is calculated by taking dividing the sum of the Chaikin #' Accumulation / Distribution line over the past \code{n} periods by the sum of #' volume over the past \code{n} periods. #' #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. #' @param volume Vector or matrix of volume observations corresponding to the #' \code{HLC} object. #' @param n Number of periods to use. #' @return A object of the same class as \code{HLC} and \code{volume} or a #' vector (if \code{try.xts} fails) containing the Chaikin Money Flow values. #' @note When Chaikin Money Flow is above/below +/- 0.25 it is a bullish/bearish #' signal. If Chaikin Money Flow remains below zero while the price is rising, #' it indicates a probable reversal. #' @author Joshua Ulrich #' @seealso See \code{\link{CLV}}, and \code{\link{chaikinAD}}. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.fmlabs.com/reference/ChaikinMoneyFlow.htm}\cr #' \url{https://www.linnsoft.com/techind/chaikin-money-flow-cmf}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_money_flow_cmf}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' cmf <- CMF(ttrc[,c("High","Low","Close")], ttrc[,"Volume"]) #' "CMF" <- function(HLC, volume, n=20) { # Chaikin Money Flow HLC <- try.xts(HLC, error=as.matrix) volume <- try.xts(volume, error=as.matrix) if(!(is.xts(HLC) && is.xts(volume))) { clv <- CLV(as.matrix(HLC)) volume <- as.matrix(volume) } clv <- CLV(HLC) cmf <- runSum(clv*volume, n) / runSum(volume, n) reclass(cmf, HLC) } ================================================ FILE: R/CMO.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Chande Momentum Oscillator #' #' The Chande Momentum Oscillator (CMO) is a modified RSI. Developed by Tushar #' S. Chande. #' #' The CMO divides the total movement by the net movement ([up - down] / [up + #' down]), where RSI divides the upward movement by the net movement (up / [up + #' down]). #' #' @param x Price, volume, etc. series that is coercible to xts or matrix. #' @param n Number of periods to use. #' @return A object of the same class as \code{x} or a vector (if \code{try.xts} #' fails) containing Chande Momentum Oscillator values. #' @note There are several ways to interpret the CMO: #' \enumerate{ #' \item Values over/under +/- 50 indicate overbought/oversold conditions. #' \item High CMO values indicate strong trends. #' \item When the CMO crosses above/below a moving average of the CMO, #' it is a buy/sell signal. #' } #' @author Joshua Ulrich #' @seealso See \code{\link{RSI}}. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.fmlabs.com/reference/CMO.htm}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' cmo <- CMO(ttrc[,"Close"]) #' "CMO" <- function(x, n=14) { # Chande Momentum Oscillator x <- try.xts(x, error=as.matrix) up <- momentum(x, n=1) dn <- ifelse(up<0, abs(up), 0) up <- ifelse(up>0, up , 0) up <- runSum(up, n) dn <- runSum(dn, n) cmo <- 100 * (up-dn)/(up+dn) if (!is.null(dim(cmo)) && ncol(cmo) == 1L) { colnames(cmo) <- "cmo" } reclass( cmo, x ) } ================================================ FILE: R/CTI.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2020 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Ehler's Correlation Trend Indicator #' #' Ehler's Correlation Trend Indicator (CTI) measures the Spearman correlation #' of the price with the ideal trend line: a straight line with increasing #' slope. #' #' The CTI measures the Spearman correlation between the price and the ideal #' trend line with slope of \code{slope}, over the past \code{n} days. #' #' See URL in references section for further details. #' #' @param price Price series that is coercible to xts or matrix. #' @param n Number of periods to use. #' @param slope Slope of desired trend. #' @return A object of the same class as \code{price} or a matrix (if #' \code{try.xts} fails) with the column: #' \describe{ #' \item{cti}{ The Correlation Trend Indicator. } #' } #' @note Positive/negative CTI values signal positive/negative correlation with #' the desired trend line slope. A simple strategy could be long when the CTI #' is positive and, short when it is negative. #' @author Ethan Smith, Joshua Ulrich #' @seealso See \code{\link{aroon}}, \code{\link{CCI}}, \code{\link{ADX}}, #' \code{\link{VHF}}, \code{\link{GMMA}}, \code{\link{TDI}} for other #' indicators that measure trend direction/strength. #' @references #' John Ehlers, Correlation Trend Indicator, Stocks & Commodities May-2020 #' The following site(s) were used to code/document this indicator:\cr #' \url{https://financial-hacker.com/petra-on-programming-a-unique-trend-indicator/}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' cti <- CTI(ttrc[,"Close"], n = 20) #' CTI <- function(price, n = 20, slope = 1) { x <- try.xts(price, error = as.matrix) y <- slope * seq_along(x) f <- function(.) { cor(.[,1], .[,2], method = "spearman") } cti <- rollapplyr(cbind(x, y), n, f, by.column = FALSE, fill = NA) if(!is.null(dim(cti))) { colnames(cti) <- "cti" } reclass(cti, x) } ================================================ FILE: R/DPO.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' De-Trended Price Oscillator #' #' The Detrended Price Oscillator (DPO) removes the trend in prices - or other #' series - by subtracting a moving average of the price from the price. #' #' The Detrended Price shows cycles and overbought / oversold conditions. #' #' @param x Price, volume, etc. series that is coercible to xts or matrix. #' @param n Number of periods for moving average. #' @param maType A function or a string naming the function to be called. #' @param shift The number of periods to shift the moving average. #' @param percent logical; if \code{TRUE}, the percentage difference between the #' slow and fast moving averages is returned, otherwise the difference between #' the respective averages is returned. #' @param \dots Other arguments to be passed to the \code{maType} function. #' @return A object of the same class as \code{x} or a vector (if \code{try.xts} #' fails) containing the DPO values. #' @note #' DPO does not extend to the last date because it is based on a displaced moving #' average. The calculation shifts the results \code{shift} periods, so the last #' \code{shift} periods will be zero.\cr #' As stated above, the DPO can be used on any univariate series, not just price. #' @section Warning: The detrended price oscillator removes the trend in the #' series by centering the moving average. Centering the moving average causes it #' to include future data. Therefore, even though this indicator looks like a #' classic oscillator, it should not be used for trading rule signals. #' @author Joshua Ulrich #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. See \code{\link{MACD}} for a general #' oscillator. #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:detrended_price_osci}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' priceDPO <- DPO(ttrc[,"Close"]) #' volumeDPO <- DPO(ttrc[,"Volume"]) #' "DPO" <- function(x, n=10, maType, shift=n/2+1, percent=FALSE, ...) { # De-Trended Price Oscillator x <- try.xts(x, error=as.matrix) maArgs <- list(n=n, ...) # Default MA if(missing(maType)) { maType <- 'SMA' } mavg <- do.call( maType, c( list(x), maArgs ) ) mavg <- lag.xts(mavg, -shift) if(percent) { DPO <- 100 * ( x[,1] / mavg - 1 ) } else { DPO <- x[,1] - mavg } reclass( DPO, x ) } ================================================ FILE: R/DVI.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' DV Intermediate Oscillator #' #' The DV Intermediate oscillator (DVI) is a very smooth momentum oscillator #' that can also be used as a trend indicator. Created by David Varadi. #' #' The DVI combines smoothed returns over different time windows and the #' relative number of up versus down days (stretch) over different time windows. #' #' @param price Price series that is coercible to xts or matrix. #' @param n Number of periods for the percent rank. #' @param wts The weight given to the smoothed returns (magnitude) component and #' the up/down days (stretch) component, respectively. #' @param smooth The number of periods to smooth price. #' @param magnitude A set of 3 periods used to smooth magnitude. #' @param stretch A set of 3 periods used to smooth stretch. #' @param exact.multiplier The weight applied to identical values in the window. #' See \code{runPercentRank}. #' @return A object of the same class as \code{price} or a vector (if #' \code{try.xts} fails) containing the DVI values. #' @author Joshua Ulrich #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://cssanalytics.wordpress.com/2009/12/13/what-is-the-dvi/}\cr #' \url{https://marketsci.wordpress.com/2010/07/27/css-analytics\%E2\%80\%99-dvi-indicator-revealed/}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' dvi <- DVI(ttrc[,"Close"]) #' DVI <- function(price, n=252, wts=c(0.8,0.2), smooth=3, magnitude=c(5,100,5), stretch=c(10,100,2), exact.multiplier=1) { # David Varadi's DVI indicator # try to convert 'price' to xts price <- try.xts(price, error=as.matrix) # ensure magnitude + stretch = 1 wts.sum <- sum(wts) wts[1] <- wts[1] / wts.sum wts[2] <- wts[2] / wts.sum # calculate magnitude, based on average price return r <- price/SMA(price,smooth)-1 mag <- SMA( ( SMA(r,magnitude[1]) + SMA(r,magnitude[2])/10 )/2, magnitude[3] ) # calculate stretch, based on whether return is +/- b <- ifelse( price > lag.xts(price), 1, -1 ) str <- SMA( ( runSum(b,stretch[1]) + runSum(b,stretch[2])/10 )/2, stretch[3] ) # calculate the DVI magnitude and stretch for each period dvi.mag <- runPercentRank(mag, n, FALSE, exact.multiplier) dvi.str <- runPercentRank(str, n, FALSE, exact.multiplier) # calculate final DVI value dvi <- wts[1] * dvi.mag + wts[2] * dvi.str result <- cbind(dvi.mag, dvi.str, dvi) colnames(result) <- c("dvi.mag", "dvi.str", "dvi") # convert final DVI, magnitude, and stretch back to # original class of 'price' reclass(result, price) } ================================================ FILE: R/DonchianChannel.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Donchian Channel #' #' Donchian Channels were created by Richard Donchian and were used to generate #' buy and sell signals for the Turtle Trading system. #' #' Donchian Channels consist of two (sometimes three) lines: #' #' The top line is the highest high of the past \code{n} periods. The bottom #' line is the lowest low of the past \code{n} periods. The middle line is the #' average of the top and bottom lines. #' #' @aliases DonchianChannel Donchian #' @param HL Object that is coercible to xts or matrix and contains High-Low #' prices. #' @param n Number of periods for moving average. #' @param include.lag Should values be lagged so that today's prices are not #' included in the calculation? See Note. #' @return A object of the same class as \code{HL} or a matrix (if #' \code{try.xts} fails) containing the columns: #' \describe{ #' \item{ high }{ The highest high series. } #' \item{ mid }{ The average of \code{high} and \code{low}. } #' \item{ low }{ The lowest low series. } #' } #' @note The default of \code{include.lag=FALSE} makes \code{DonchainChannel} #' consistent with other \pkg{TTR} functions, in that it includes the current #' period in the calculation. #' #' The default is different than the original calculation, which would calculate #' the indicator using periods t-1 through t-n. Setting \code{include.lag=TRUE} #' will return the result of the original calculation. #' #' The default of this argument may change in the future. #' @author Joshua Ulrich #' @seealso See \code{\link{BBands}}. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.linnsoft.com/techind/donchian-channels}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' dc <- DonchianChannel( ttrc[,c("High","Low")] ) #' 'DonchianChannel' <- function(HL, n=10, include.lag=FALSE) { # Donchian Channel # Notes from John Bollinger: # # "In the old paper-calculation days you would calculate the numbers # after the close by hand and for use in the next day's trading to gauge # the "n-day" breakouts and you would have used n-days worth of data the # calc. Thus an n-day calc with a lag of one would be consistent with # practice in Donchian's day. (Total window of n+1.) Another example are # the floor traders numbers or pivots, which are calculated from the # prior period's data for use on the current period. In both case # including the current period in the calculation would not be correct." HL <- try.xts(HL, error=as.matrix) if(!(NCOL(HL) %in% c(1,2))) { stop("Price series must be either High-Low, or Close/univariate.") } if(NCOL(HL)==2) { hi <- HL[,1] lo <- HL[,2] } else { hi <- HL lo <- HL } high <- runMax(hi,n) low <- runMin(lo,n) mid <- (high+low)/2 result <- cbind(high,mid,low) colnames(result) <- c("high","mid","low") if(include.lag) { # use lag.xts in case 'result' is a matrix result <- lag.xts(result) } reclass(result, HL) } ================================================ FILE: R/EMV.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Arms' Ease of Movement Value #' #' Arms' Ease of Movement Value (EMV) emphasizes days where the security moves #' easily and minimizes days where the security does not move easily. Developed #' by Richard W. Arms, Jr. #' #' The EMV is calculated by dividing the midpoint ([high + low]/2) move by the #' 'Box Ratio' (volume divided by the high minus low). #' #' @param HL Object that is coercible to xts or matrix and contains High-Low #' prices. #' @param volume Vector or matrix of volume observations corresponding to the #' \code{HL} object. #' @param n Number of periods for moving average. #' @param maType A function or a string naming the function to be called. #' @param vol.divisor An increment to make the results larger and easier to work #' with. #' @param \dots Other arguments to be passed to the \code{maType} function. #' @return A object of the same class as \code{HL} and \code{volume} or a matrix #' (if \code{try.xts} fails) containing the columns: #' \describe{ #' \item{ emv }{ The ease of movement values. } #' \item{ maEMV }{ The smoothed (as specified by \code{ma}) ease of movement values. } #' } #' @note A buy/sell signal is generated when the EMV crosses above/below zero. #' When the EMV hovers around zero, there are small price movements and/or high #' volume, and the price is not moving easily. #' @author Joshua Ulrich #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.fmlabs.com/reference/ArmsEMV.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=51}\cr #' \url{https://www.linnsoft.com/techind/arms-ease-movement}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' emv <- EMV(ttrc[,c("High","Low")], ttrc[,"Volume"]) #' "EMV" <- function(HL, volume, n=9, maType, vol.divisor=10000, ...) { # Arms' Ease of Movement Value if( missing(HL) || missing(volume) ) stop("High-Low matrix (HL) and volume vector must be specified.") HL <- try.xts(HL, error=as.matrix) volume <- try.xts(volume, error=as.matrix) if(!(is.xts(HL) && is.xts(volume))) { HL <- as.matrix(HL) volume <- as.matrix(volume) } mid <- ( HL[,1] + HL[,2] ) / 2 volume <- volume / vol.divisor emv <- momentum(mid, n=1, na.pad=TRUE) / ( volume / ( HL[,1] - HL[,2] ) ) maArgs <- list(n=n, ...) # Default MA if(missing(maType)) { maType <- 'SMA' } maEMV <- do.call( maType, c( list(emv), maArgs ) ) result <- cbind(emv,maEMV) colnames(result) <- c('emv','maEMV') reclass( result, HL ) } ================================================ FILE: R/GMMA.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Guppy Multiple Moving Averages #' #' Calculate the Guppy Multiple Moving Average of a series. #' #' The Guppy Multiple Moving Average signals a changing trend when the #' \code{short} and \code{long} groups of moving averages intersect. An up/down #' trend exists when the short/long-term moving averages are greater than the #' long/short-term averages. #' #' @aliases GMMA Guppy guppy #' @param x Price, volume, etc. series that is coercible to xts or matrix. #' @param short Vector of short-term periods. #' @param long Vector of long-term periods. #' @param maType Either: #' \enumerate{ #' \item A function or a string naming the function to be called. #' \item A \emph{list} with the first component like (1) above, and #' additional parameters specified as \emph{named} components. #' See Examples. #' } #' @return A object of the same class as \code{x} or \code{price} or a vector #' (if \code{try.xts} fails) containing the Guppy Multiple Moving Average. #' @author Joshua Ulrich #' @seealso See \code{\link{aroon}}, \code{\link{CCI}}, \code{\link{ADX}}, #' \code{\link{VHF}}, \code{\link{TDI}} for other indicators that measure trend #' direction/strength. #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://www.investopedia.com/terms/g/guppy-multiple-moving-average.asp}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' gmma <- GMMA(ttrc[,"Close"]) #' "GMMA" <- function(x, short=c(3,5,8,10,12,15), long=c(30,35,40,45,50,60), maType) { # Guppy Multiple Moving Average x <- try.xts(x, error=as.matrix) # Default MA if(missing(maType)) { maType <- 'EMA' } fn <- function(g) { do.call(maType, list(x,n=g)) } gmma <- do.call(cbind, lapply(c(short,long), fn)) colnames(gmma) <- c(paste('short lag',short),paste('long lag',long)) reclass(gmma, x) } ================================================ FILE: R/KST.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Know Sure Thing #' #' The Know Sure Thing (KST) is a smooth, summed, rate of change indicator. #' Developed by Martin Pring. #' #' For each day (week, month, etc.), the KST calculates the ROC over several #' periods. Those ROCs are smoothed using the given moving averages, then #' multiplied by their respective weighting values. The resulting values are #' summed for each day (month, week, etc.). #' #' @param price Price series that is coercible to xts or matrix. #' @param n A vector of the number of periods to use in the MA calculations. #' @param nROC A vector of the number of periods to use in the ROC calculations. #' @param nSig The number of periods to use for the KST signal line. #' @param maType Either: #' \enumerate{ #' \item A function or a string naming the function to be called. #' \item A \emph{list} with the first component like (1) above, and #' additional parameters specified as \emph{named} components. #' See Examples. #' } #' @param wts A vector the same length as \code{n}, of the weight for each #' period (need not sum to one). #' @param \dots Other arguments to be passed to the \code{maType} function in #' case (1) above. #' @return A object of the same class as \code{price} or a vector (if #' \code{try.xts} fails) containing the Know Sure Thing values. #' @note The KST indicates bullish/bearish momentum as it crosses above/below #' its moving average. Because the KST tends to lead price action, look for #' trend confirmation in the price. #' #' The default arguments are for the daily KST. There is also the Long-Term #' KST, with arguments: \code{n=c(9, 12, 18, 24)} - where the periods are #' months, not days - and the moving average periods are 6, 6, 6, and 9 months, #' respectively. #' @author Joshua Ulrich #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. See \code{\link{ROC}} for the #' rate-of-change function. See \code{\link{MACD}} for a generic oscillator. #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://web.archive.org/web/20110715112957/http://www.pring.com/movieweb/daily_kst.htm}\cr #' \url{https://web.archive.org/web/20100101162707/http://www.pring.com/movieweb/KST_MCM.htm}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' kst <- KST(ttrc[,"Close"]) #' #' kst4MA <- KST(ttrc[,"Close"], #' maType=list(list(SMA),list(EMA),list(DEMA),list(WMA))) #' "KST" <- function(price, n=c(10,10,10,15), nROC=c(10,15,20,30), nSig=9, maType, wts=1:NROW(n), ...) { # Know Sure Thing # Technical Analysis Explained: The Successful Investor's Guide to # Spotting Investment Trends and Turning Points # Martin J. Pring # http://www.pring.com/index.html # Daily: http://www.pring.com/movieweb/daily_kst.htm # Long-Term: http://www.pring.com/articles/article28.htm # Daily KST # MA(ROC(10)10) + MA(ROC(15)10) + MA(ROC(20)10) + MA(ROC(30)15) # # Intermediate KST # MA(ROC(10)10) + MA(ROC(13)13) + MA(ROC(15)15) + MA(ROC(20)20) # # Long-Term Monthly KST # MA(ROC(9)6) + MA(ROC(12)6) + MA(ROC(18)6) + MA(ROC(24)9) if( !all.equal(NROW(n), NROW(wts), NROW(nROC)) ) { stop("'n', 'nROC', and 'wts' must be the same length.") } else { N <- NROW(n) } #price <- as.vector(price) ret <- NULL # Default MA if(missing(maType)) { maType <- 'SMA' } # Case of two different 'maType's for both MAs. if( is.list(maType) ) { # Make sure maType is a list of lists maTypeInfo <- sapply(maType,is.list) if( !(all(maTypeInfo) && length(maTypeInfo) == N) ) { stop("If \'maType\' is a list, you must specify\n ", "the same number of MAs as elements in \'n\' and\n ", "\'nROC\' (see Examples section of ?KST)") } # If MA function has 'n' arg, see if it's populated in maType; # if it isn't, populate it with formal 'n' for(i in 1:length(maType)) { if( !is.null( formals(maType[[i]][[1]])$n ) && is.null( maType[[i]]$n ) ) { maType[[i]]$n <- n[i] } roc <- ROC(price, nROC[i], na.pad=TRUE) ma.roc <- do.call( maType[[i]][[1]], c( list(roc), maType[[i]][-1] ) ) * wts[i] ret <- cbind( ret, ma.roc ) } } # Case of one 'maType' for both MAs. else { for(i in 1:NROW(n)) { roc <- ROC(price, nROC[i], na.pad=TRUE) ma.roc <- do.call( maType, c( list(roc), list(n=n[i], ...) ) ) * wts[i] ret <- cbind( ret, ma.roc ) } } if(is.xts(ret)) { kst <- xts(100 * rowSums(ret),index(ret)) } else { kst <- 100 * rowSums(ret) } if( is.list(maType) ) { sigMA <- length(maType) signal <- do.call( maType[[sigMA]][[1]], c( list(kst), maType[[sigMA]][-1] ) ) } else { signal <- do.call( maType, c( list(kst), list(n=nSig, ...) ) ) } result <- cbind( kst, signal ) colnames(result) <- c( "kst", "signal" ) return( result ) } ================================================ FILE: R/MACD.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' MACD Oscillator #' #' The MACD was developed by Gerald Appel and is probably the most popular price #' oscillator. The MACD function documented in this page compares a fast moving #' average (MA) of a series with a slow MA of the same series. It can be used #' as a generic oscillator for any univariate series, not only price. #' #' The MACD function either subtracts the fast MA from the slow MA, or finds the #' rate of change between the fast MA and the slow MA. #' #' @param x Object that is coercible to xts or matrix; usually price, but can be #' volume, etc. #' @param nFast Number of periods for fast moving average. #' @param nSlow Number of periods for slow moving average. #' @param nSig Number of periods for signal moving average. #' @param maType Either: #' \enumerate{ #' \item A function or a string naming the function to be called. #' \item A \emph{list} with the first component like (1) above, and #' additional parameters specified as \emph{named} components. #' See Examples. #' } #' @param percent logical; if \code{TRUE}, the percentage difference between the #' fast and slow moving averages is returned, otherwise the difference between #' the respective averages is returned. #' @param \dots Other arguments to be passed to the \code{maType} function in #' case (1) above. #' @return A object of the same class as \code{x} or a matrix (if \code{try.xts} #' fails) containing the columns: #' \describe{ #' \item{ macd }{ The price (volume, etc.) oscillator. } #' \item{ signal }{ The oscillator signal line (a moving average of the oscillator). } #' } #' @note The MACD is a special case of the general oscillator applied to price. #' The MACD can be used as a general oscillator applied to any series. Time #' periods for the MACD are often given as 26 and 12, but the original formula #' used exponential constants of 0.075 and 0.15, which are closer to #' 25.6667 and 12.3333 periods. #' @author Joshua Ulrich #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. #' @references The following site(s) were used to code/document this #' indicator: #' \cr Moving Average Convergence/Divergence (MACD):\cr #' \url{https://www.fmlabs.com/reference/MACD.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=66}\cr #' \url{https://www.linnsoft.com/techind/macd}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:moving_average_convergence_divergence_macd}\cr #' \cr Price Oscillator:\cr #' \url{https://www.fmlabs.com/reference/PriceOscillator.htm}\cr #' \url{https://www.fmlabs.com/reference/PriceOscillatorPct.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=94}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:price_oscillators_ppo}\cr #' \cr Volume Oscillator:\cr #' \url{https://www.fmlabs.com/reference/PVO.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=122}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' #' macd <- MACD( ttrc[,"Close"], 12, 26, 9, maType="EMA" ) #' macd2 <- MACD( ttrc[,"Close"], 12, 26, 9, #' maType=list(list(SMA), list(EMA, wilder=TRUE), list(SMA)) ) #' "MACD" <- function(x, nFast=12, nSlow=26, nSig=9, maType, percent=TRUE, ...) { # Oscillators # WISHLIST: # Add capability to allow 'ma.slow' and 'ma.fast' to be vectors # containing MAs, which would allow the oscillator to be constructed # using MAs of different prices. # Default MA if(missing(maType)) { maType <- 'EMA' } # Case of two different 'maType's for both MAs. if( is.list(maType) ) { # Make sure maType is a list of lists maTypeInfo <- sapply(maType,is.list) if( !(all(maTypeInfo) && length(maTypeInfo) == 3) ) { stop("If \'maType\' is a list, you must specify\n ", "*three* MAs (see Examples section of ?MACD)") } # If MA function has 'n' arg, see if it's populated in maType; # if it isn't, populate it with function's formal 'n' if( !is.null( formals(maType[[1]][[1]])$n ) && is.null( maType[[1]]$n ) ) { maType[[1]]$n <- nFast } if( !is.null( formals(maType[[2]][[1]])$n ) && is.null( maType[[2]]$n ) ) { maType[[2]]$n <- nSlow } if( !is.null( formals(maType[[3]][[1]])$n ) && is.null( maType[[3]]$n ) ) { maType[[3]]$n <- nSig } mavg.fast <- do.call( maType[[1]][[1]], c( list(x), maType[[1]][-1] ) ) mavg.slow <- do.call( maType[[2]][[1]], c( list(x), maType[[2]][-1] ) ) } # Case of one 'maType' for both MAs. else { mavg.fast <- do.call( maType, c( list(x), list(n=nFast, ...) ) ) mavg.slow <- do.call( maType, c( list(x), list(n=nSlow, ...) ) ) } if(percent) { macd <- 100 * ( mavg.fast / mavg.slow - 1 ) } else { macd <- mavg.fast - mavg.slow } if( is.list(maType) ) { signal <- do.call( maType[[3]][[1]], c( list( macd ), maType[[3]][-1] ) ) } else signal <- do.call( maType, c( list( macd ), list(n=nSig, ...) ) ) result <- cbind( macd, signal ) colnames(result) <- c( "macd", "signal" ) return( result ) } ================================================ FILE: R/MFI.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Money Flow Index #' #' The MFI is a ratio of positive and negative money flow over time. #' #' Money Flow (MF) is the product of price and volume. Positive/negative MF #' occur when today's price is higher/lower than yesterday's price. The MFI is #' calculated by dividing positive MF by negative MF for the past \code{n} #' periods. It is then scaled between 0 and 100. #' #' MFI is usually calculated using the typical price, but if a univariate series #' (e.g. Close, Weighted Close, Median Price, etc.) is provided, it will be used #' instead. #' #' @aliases MFI moneyFlow #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. If only a univariate series is given, it will be #' used. See details. #' @param volume Vector or matrix of volume observations corresponding to #' \code{HLC} object. #' @param n Number of periods to use. #' @return A object of the same class as \code{HLC} and \code{volume} or a #' vector (if \code{try.xts} fails) containing the MFI values. #' @note Divergence between MFI and price can be indicative of a reversal. In #' addition, values above/below 80/20 indicate market tops/bottoms. #' @author Joshua Ulrich #' @seealso See \code{\link{OBV}} and \code{\link{CMF}}. #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://www.fmlabs.com/reference/default.htm?url=MoneyFlowIndex.htm}\cr #' \url{https://www.linnsoft.com/techind/money-flow-index-mfi}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:money_flow_index_mfi}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' mfi <- MFI(ttrc[,c("High","Low","Close")], ttrc[,"Volume"]) #' "MFI" <- function(HLC, volume, n=14) { # Money Flow Index HLC <- try.xts(HLC, error=as.matrix) volume <- try.xts(volume, error=as.matrix) if(!(is.xts(HLC) && is.xts(volume))) { HLC <- as.matrix(HLC) volume <- as.matrix(volume) } if(NCOL(HLC)==3) { if(is.xts(HLC)) { HLC <- xts(apply(HLC, 1, mean),index(HLC)) } else { HLC <- apply(HLC, 1, mean) } } else if(NCOL(HLC)!=1) { stop("Price series must be either High-Low-Close, or Close/univariate.") } if(is.xts(HLC)) { priceLag <- lag.xts(HLC) } else { priceLag <- c( NA, HLC[-NROW(HLC)] ) } # Calculate Money Flow mf <- HLC * volume # Calculate positive and negative Money Flow pmf <- ifelse( HLC > priceLag, mf, 0 ) nmf <- ifelse( HLC < priceLag, mf, 0 ) # Calculate Money Ratio and Money Flow Index num <- runSum( pmf, n ) den <- runSum( nmf, n ) mr <- num / den mfi <- 100 - ( 100 / ( 1 + mr ) ) mfi[0 == den] <- 100 mfi[0 == den & 0 == num] <- 50 if(is.xts(mfi)) colnames(mfi) <- 'mfi' reclass( mfi, HLC ) } ================================================ FILE: R/MovingAverages.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Moving Averages #' #' Calculate various moving averages (MA) of a series. #' #' \code{SMA} calculates the arithmetic mean of the series over the past #' \code{n} observations. #' #' \code{EMA} calculates an exponentially-weighted mean, giving more weight to #' recent observations. See Warning section below. #' #' \code{WMA} is similar to an EMA, but with linear weighting if the length of #' \code{wts} is equal to \code{n}. If the length of \code{wts} is equal to the #' length of \code{x}, the WMA will use the values of \code{wts} as weights. #' #' \code{DEMA} is calculated as: \code{DEMA = (1 + v) * EMA(x,n) - #' EMA(EMA(x,n),n) * v} (with the corresponding \code{wilder} and \code{ratio} #' arguments). #' #' \code{EVWMA} uses volume to define the period of the MA. #' #' \code{ZLEMA} is similar to an EMA, as it gives more weight to recent #' observations, but attempts to remove lag by subtracting data prior to #' \code{(n-1)/2} periods (default) to minimize the cumulative effect. #' #' \code{VWMA} and \code{VWAP} calculate the volume-weighted moving average #' price. #' #' \code{HMA} a WMA of the difference of two other WMAs, making it very #' reponsive. #' #' \code{ALMA} inspired by Gaussian filters. Tends to put less weight on most #' recent observations, reducing tendency to overshoot. #' #' @aliases MovingAverages SMA EMA WMA DEMA GD T3 EVWMA ZLEMA VWAP VWMA MA #' @param x Price, volume, etc. series that is coercible to xts or matrix. #' @param price Price series that is coercible to xts or matrix. #' @param volume Volume series that is coercible to xts or matrix, that #' corresponds to price series, or a constant. See Notes. #' @param n Number of periods to average over. Must be between 1 and #' \code{nrow(x)}, inclusive. #' @param v The 'volume factor' (a number in [0,1]). See Notes. #' @param wts Vector of weights. Length of \code{wts} vector must equal the #' length of \code{x}, or \code{n} (the default). #' @param wilder logical; if \code{TRUE}, a Welles Wilder type EMA will be #' calculated; see notes. #' @param ratio A smoothing/decay ratio. \code{ratio} overrides \code{wilder} #' in \code{EMA}. #' @param offset Percentile at which the center of the distribution should occur. #' @param sigma Standard deviation of the distribution. #' @param \dots any other passthrough parameters #' @return A object of the same class as \code{x} or \code{price} or a vector #' (if \code{try.xts} fails) containing the columns: #' \describe{ #' \item{SMA}{ Simple moving average. } #' \item{EMA}{ Exponential moving average. } #' \item{WMA}{ Weighted moving average. } #' \item{DEMA}{ Double-exponential moving average. } #' \item{EVWMA}{ Elastic, volume-weighted moving average. } #' \item{ZLEMA}{ Zero lag exponential moving average. } #' \item{VWMA}{ Volume-weighed moving average (same as \code{VWAP}). } #' \item{VWAP}{ Volume-weighed average price (same as \code{VWMA}). } #' \item{VWA}{ Variable-length moving average. } #' \item{HMA}{ Hull moving average. } #' \item{ALMA}{ Arnaud Legoux moving average. } #' } #' @note For \code{EMA}, \code{wilder=FALSE} (the default) uses an exponential #' smoothing ratio of \code{2/(n+1)}, while \code{wilder=TRUE} uses Welles #' Wilder's exponential smoothing ratio of \code{1/n}. The \code{EMA} result #' is initialized with the \code{n}-period sample average at period \code{n}. #' The exponential decay is applied from that point forward. #' #' Since \code{WMA} can accept a weight vector of length equal to the length of #' \code{x} or of length \code{n}, it can be used as a regular weighted moving #' average (in the case \code{wts=1:n}) or as a moving average weighted by #' volume, another indicator, etc. #' #' Since \code{DEMA} allows adjusting \code{v}, it is technically Tim Tillson's #' generalized DEMA (GD). When \code{v=1} (the default), the result is the #' standard DEMA. When \code{v=0}, the result is a regular EMA. All other #' values of \code{v} return the GD result. This function can be used to #' calculate Tillson's T3 indicator (see example below). Thanks to John Gavin #' for suggesting the generalization. #' #' For \code{EVWMA}, if \code{volume} is a series, \code{n} should be chosen so #' the sum of the volume for \code{n} periods approximates the total number of #' outstanding shares for the security being averaged. If \code{volume} is a #' constant, it should represent the total number of outstanding shares for the #' security being averaged. #' @section Warning : Some indicators (e.g. EMA, DEMA, EVWMA, etc.) are #' calculated using the indicators' own previous values, and are therefore #' unstable in the short-term. As the indicator receives more data, its output #' becomes more stable. See example below. #' @author Joshua Ulrich, Ivan Popivanov (HMA, ALMA) #' @seealso See \code{\link{wilderSum}}, which is used in calculating a Welles #' Wilder type MA. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.fmlabs.com/reference/ExpMA.htm}\cr #' \url{https://www.fmlabs.com/reference/WeightedMA.htm}\cr #' \url{https://www.fmlabs.com/reference/DEMA.htm}\cr #' \url{https://www.fmlabs.com/reference/T3.htm}\cr #' \url{https://www.linnsoft.com/techind/evwma-elastic-volume-weighted-moving-average}\cr #' \url{https://www.fmlabs.com/reference/ZeroLagExpMA.htm}\cr #' \url{https://www.fmlabs.com/reference/VIDYA.htm}\cr #' \url{https://www.traderslog.com/hullmovingaverage}\cr #' \url{https://web.archive.org/web/20180222085959/http://arnaudlegoux.com/}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' ema.20 <- EMA(ttrc[,"Close"], 20) #' sma.20 <- SMA(ttrc[,"Close"], 20) #' dema.20 <- DEMA(ttrc[,"Close"], 20) #' evwma.20 <- EVWMA(ttrc[,"Close"], ttrc[,"Volume"], 20) #' zlema.20 <- ZLEMA(ttrc[,"Close"], 20) #' alma <- ALMA(ttrc[,"Close"]) #' hma <- HMA(ttrc[,"Close"]) #' #' ## Example of Tim Tillson's T3 indicator #' T3 <- function(x, n=10, v=1) DEMA(DEMA(DEMA(x,n,v),n,v),n,v) #' t3 <- T3(ttrc[,"Close"]) #' #' ## Example of short-term instability of EMA #' ## (and other indicators mentioned above) #' x <- rnorm(100) #' tail( EMA(x[90:100],10), 1 ) #' tail( EMA(x[70:100],10), 1 ) #' tail( EMA(x[50:100],10), 1 ) #' tail( EMA(x[30:100],10), 1 ) #' tail( EMA(x[10:100],10), 1 ) #' tail( EMA(x[ 1:100],10), 1 ) #' #' @rdname MovingAverages "SMA" <- function(x, n=10, ...) { # Simple Moving Average ma <- runMean( x, n ) if(!is.null(dim(ma))) { colnames(ma) <- "SMA" } return(ma) } #-------------------------------------------------------------------------# #' @rdname MovingAverages "EMA" <- function (x, n=10, wilder=FALSE, ratio=NULL, ...) { # Exponential Moving Average x <- try.xts(x, error=as.matrix) if( n < 1 || n > NROW(x) ) stop(sprintf("n = %d is outside valid range: [1, %d]", n, NROW(x))) # If ratio is specified, and n is not, set n to approx 'correct' # value backed out from ratio if(missing(n) && !missing(ratio)) n <- NULL # Call C routine ma <- .Call(C_ema, x, n, ratio, isTRUE(wilder)) ma <- reclass(ma,x) if(!is.null(dim(ma))) { colnames(ma) <- "EMA" } return(ma) } #-------------------------------------------------------------------------# #' @rdname MovingAverages "DEMA" <- function(x, n=10, v=1, wilder=FALSE, ratio=NULL) { # Double Exponential Moving Average # Thanks to John Gavin for the v-factor generalization x <- try.xts(x, error=as.matrix) if( n < 1 || n > NROW(x) ) stop(sprintf("n = %d is outside valid range: [1, %d]", n, NROW(x))) if(NCOL(x) > 1) { stop("ncol(x) > 1. DEMA only supports univariate 'x'") } if(v < 0 || v > 1) { stop("Please ensure 0 <= v <= 1") } if(missing(n) && !missing(ratio)) n <- NULL # Call C routine ma1 <- .Call(C_ema, x, n, ratio, isTRUE(wilder)) d <- .Call(C_ema, ma1, n, ratio, isTRUE(wilder)) dema <- (1 + v) * ma1 - d * v dema <- reclass(dema, x) if(!is.null(dim(dema))) { colnames(dema) <- "DEMA" } return(dema) } #-------------------------------------------------------------------------# #' @rdname MovingAverages "WMA" <- function(x, n=10, wts=1:n, ...) { # Weighted Moving Average x <- try.xts(x, error=as.matrix) wts <- try.xts(wts, error=as.matrix) if( !any( NROW(wts) == c( NROW(x), n ) ) ) stop("Length of 'wts' must equal the length of 'x' or 'n'") if( n < 1 || n > NROW(x) ) stop(sprintf("n = %d is outside valid range: [1, %d]", n, NROW(x))) if(NCOL(x) > 1 || NCOL(wts) > 1) { stop("ncol(x) > 1 or ncol(wts) > 1. WMA only supports univariate 'x' and 'w'") } # Count NAs, ensure they're only at beginning of data, then remove. NAx <- sum( is.na(x) ) NAw <- sum( is.na(wts) ) NAs <- max( NAx, NAw ) if( NAs > 0 ) { if( any( is.na( x[-(1:NAx)]) ) ) stop("'x' contains non-leading NAs") if( any( is.na(wts[-(1:NAw)]) ) ) stop("'wts' contains non-leading NAs") } if( NROW(wts) == n ) { NAs <- NAx if( any(is.na(wts)) ) stop("'wts' vector of length 'n' cannot have NA values") # Call C routine ma <- .Call(C_wma, x, wts, n) } else { xw <- cbind(x, wts) ma <- runSum( xw[,1]*xw[,2], n) / runSum(xw[,2], n) } # replace 1:(n-1) with NAs and prepend NAs from original data ma[1:(n-1)] <- NA # Convert back to original class ma <- reclass(ma,x) if(!is.null(dim(ma))) { colnames(ma) <- "WMA" } return(ma) } #-------------------------------------------------------------------------# #' @rdname MovingAverages "EVWMA" <- function(price, volume, n=10, ...) { # Elastic, Volume-Weighted Moving Average price <- try.xts(price, error=as.matrix) volume <- try.xts(volume, error=as.matrix) if( !any( NROW(volume) == c( NROW(price), 1 ) ) ) stop("Length of 'volume' must equal 1 or the length of 'price'") if( n < 1 || n > NROW(price) ) stop(sprintf("n = %d is outside valid range: [1, %d]", n, NROW(price))) if(NCOL(price) > 1 || NCOL(volume) > 1) { stop("ncol(price) > 1 or ncol(volume) > 1.", " EVWMA only supports univariate 'price' and 'volume'") } pv <- cbind(price, volume) if( any(nNonNA <- n > colSums(!is.na(pv))) ) stop("n > number of non-NA values in ", paste(c("price","volume")[which(nNonNA)], collapse=", ")) # Call C routine ma <- .Call(C_evwma, pv[,1], pv[,2], n) # Convert back to original class ma <- reclass(ma, price) if(!is.null(dim(ma))) { colnames(ma) <- "EVWMA" } return(ma) } #-------------------------------------------------------------------------# #' @rdname MovingAverages "ZLEMA" <- function (x, n=10, ratio=NULL, ...) { # Zero-Lag Exponential Moving Average x <- try.xts(x, error=as.matrix) if(NCOL(x) > 1) { stop("ncol(x) > 1. ZLEMA only supports univariate 'x'") } # If ratio is specified, and n is not, set n to approx 'correct' # value backed out from ratio if(missing(n) && !missing(ratio)) n <- NULL # Call C routine ma <- .Call(C_zlema, x, n, ratio) # Convert back to original class ma <- reclass(ma,x) if(!is.null(dim(ma))) { colnames(ma) <- "ZLEMA" } return(ma) } #-------------------------------------------------------------------------# #' @rdname MovingAverages "VWAP" <- "VWMA" <- function(price, volume, n=10, ...) { # Volume-weighted average price # Volume-weighted moving average res <- WMA(price, n=n, volume) if(!is.null(dim(res))) { colnames(res) <- "VWAP" } return(res) } #-------------------------------------------------------------------------# #' @rdname MovingAverages "HMA" <- function(x, n=20, ...) { # Hull Moving Average madiff <- 2 * WMA(x, n = trunc(n / 2), ...) - WMA(x, n = n, ...) hma <- WMA(madiff, n = trunc(sqrt(n)), ...) if(!is.null(dim(hma))) { colnames(hma) <- "HMA" } return(hma) } #-------------------------------------------------------------------------# #' @rdname MovingAverages "ALMA" <- function(x, n=9, offset=0.85, sigma=6, ...) { # ALMA (Arnaud Legoux Moving Average) x <- try.xts(x, error=as.matrix) if(offset < 0 || offset > 1) { stop("Please ensure 0 <= offset <= 1") } if(sigma <= 0) stop("sigma must be > 0") m <- floor(offset*(n-1)) s <- n/sigma wts <- exp(-((seq(0,n-1)-m)^2)/(2*s*s)) sumWeights <- sum(wts) if(sumWeights != 0) wts <- wts/sumWeights alma <- x * NA_real_ for(i in seq_len(NCOL(x))) { alma[,i] <- WMA(x[,i], n, wts) } if(!is.null(dim(alma))) { colnames(alma) <- "ALMA" } reclass(alma, x) } ================================================ FILE: R/OBV.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' On Balance Volume (OBV) #' #' On Balance Volume (OBV) is a measure of the money flowing into or out of a #' security. It is similar to Chaikin Accumulation / Distribution. #' #' OBV is calculated by adding (subtracting) each day's volume to a running #' cumulative total when the security's price closes higher (lower). #' #' @param price Price series that is coercible to xts or matrix. #' @param volume Volume series that is coercible to xts or matrix, that #' corresponds to price object. #' @return A object of the same class as \code{price} and \code{volume} or a #' vector (if \code{try.xts} fails) containing the OBV values. #' @note OBV is usually compared with the price chart of the underlying security #' to look for divergences/confirmation. #' @author Joshua Ulrich #' @seealso See \code{\link{chaikinAD}}. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.fmlabs.com/reference/OBV.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=82}\cr #' \url{https://www.linnsoft.com/techind/balance-open-interest}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:on_balance_volume_obv}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' obv <- OBV(ttrc[,"Close"], ttrc[,"Volume"]) #' "OBV" <- function(price, volume) { # On Balance Volume price <- try.xts(price, error=as.matrix) volume <- try.xts(volume, error=as.matrix) if(!(is.xts(price) && is.xts(volume))) { price <- as.vector(price) volume <- as.vector(volume) } prChg <- ROC(price) obv <- c( volume[1], ifelse( prChg > 0, volume, -volume )[-1] ) # OBV[t] = OBV[t-1] if price change is equal to zero obv[abs(prChg) < sqrt(.Machine$double.eps)] <- 0 obv <- cumsum( obv ) if(is.xts(obv)) { obv <- xts(obv,index(price)) colnames(obv) <- 'obv' } reclass( obv, price ) } ================================================ FILE: R/RSI.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Relative Strength Index #' #' The Relative Strength Index (RSI) calculates a ratio of the recent upward #' price movements to the absolute price movement. Developed by J. Welles #' Wilder. #' #' The RSI calculation is \code{RSI = 100 - 100 / ( 1 + RS )}, where \code{RS} #' is the smoothed ratio of 'average' gains over 'average' losses. The #' 'averages' aren't true averages, since they're divided by the value of #' \code{n} and not the number of periods in which there are gains/losses. #' #' @param price Price series that is coercible to xts or matrix. #' @param n Number of periods for moving averages. #' @param maType Either: #' \enumerate{ #' \item A function or a string naming the function to be called. #' \item A \emph{list} with the first component like (1) above, and #' additional parameters specified as \emph{named} components. #' See Examples. #' } #' @param \dots Other arguments to be passed to the \code{maType} function in #' case (1) above. #' @return A object of the same class as \code{price} or a vector (if #' \code{try.xts} fails) containing the RSI values. #' @note The RSI is usually interpreted as an overbought/oversold (over 70 / #' below 30) indicator. Divergence with price may also be useful. For example, #' if price is making new highs/lows, but RSI is not, it could indicate a #' reversal. #' #' You can calculate a stochastic RSI by using the function \code{\link{stoch}} #' on RSI values. #' @author Joshua Ulrich #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. See \code{\link{CMO}} for a variation on #' RSI. #' @references The following site(s) were used to code/document this #' indicator: #' \cr Relative Strength Index:\cr #' \url{https://www.fmlabs.com/reference/RSI.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=100}\cr #' \url{https://www.linnsoft.com/techind/relative-strength-index-rsi}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:relative_strength_index_rsi}\cr #' \cr Stochastic RSI:\cr #' \url{https://www.fmlabs.com/reference/StochRSI.htm}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:stochrsi}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' price <- ttrc[,"Close"] #' #' # Default case #' rsi <- RSI(price) #' #' # Case of one 'maType' for both MAs #' rsiMA1 <- RSI(price, n=14, maType="WMA", wts=ttrc[,"Volume"]) #' #' # Case of two different 'maType's for both MAs #' rsiMA2 <- RSI(price, n=14, maType=list(maUp=list(EMA),maDown=list(WMA))) #' #' "RSI" <- function(price, n=14, maType, ...) { price <- try.xts(price, error=as.matrix) up <- momentum(price, n=1, na.pad=TRUE) which.dn <- which(up < 0) dn <- up*0 dn[which.dn] <- -up[which.dn] up[which.dn] <- 0 maArgs <- list(n=n, ...) # Default Welles Wilder EMA if(missing(maType)) { maType <- 'EMA' if(is.null(maArgs$wilder)) { # do not overwrite user-provided value maArgs$wilder <- TRUE } } # Case of two different 'maType's for both MAs. # e.g. RSI(price, n=14, maType=list(maUp=list(EMA,ratio=1/5), maDown=list(WMA,wts=1:10)) ) if( is.list(maType) ) { # Make sure maType is a list of lists maTypeInfo <- sapply(maType,is.list) if( !(all(maTypeInfo) && length(maTypeInfo) == 2) ) { stop("If \'maType\' is a list, you must specify\n ", "*two* MAs (see Examples section of ?RSI)") } # If MA function has 'n' arg, see if it's populated in maType; # if it isn't, populate it with RSI's formal 'n' for(i in 1:length(maType)) { if( !is.null( formals(maType[[i]][[1]])$n ) && is.null( maType[[i]]$n ) ) { maType[[i]]$n <- n } mavgUp <- do.call( maType[[1]][[1]], c( list(up), maType[[1]][-1] ) ) mavgDn <- do.call( maType[[2]][[1]], c( list(dn), maType[[2]][-1] ) ) } } # Case of one 'maType' for both MAs. # e.g. RSI(price, n=14, maType="WMA", wts=volume ) else { mavgUp <- do.call( maType, c( list(up), maArgs ) ) mavgDn <- do.call( maType, c( list(dn), maArgs ) ) } rsi <- 100 * mavgUp / ( mavgUp + mavgDn ) if (!is.null(dim(rsi)) && ncol(rsi) == 1L) { colnames(rsi) <- "rsi" } reclass( rsi, price ) } ================================================ FILE: R/SAR.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Parabolic Stop-and-Reverse #' #' The Parabolic Stop-and-Reverse calculates a trailing stop. Developed by J. #' Welles Wilder. #' #' The calculation for the SAR is quite complex. See the URLs in the references #' section for calculation notes. #' #' The SAR assumes that you are always in the market, and calculates the Stop #' And Reverse point when you would close a long position and open a short #' position or vice versa. #' #' @param HL Object that is coercible to xts or matrix and contains High-Low #' prices. #' @param accel accel[1]: Acceleration factor.\cr accel[2]: Maximum acceleration #' factor. #' @return A object of the same class as \code{HL} or a vector (if #' \code{try.xts} fails) containing the Parabolic Stop and Reverse values. #' @author Joshua Ulrich #' @seealso See \code{\link{ATR}} and \code{\link{ADX}}, which were also #' developed by Welles Wilder. #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://www.linnsoft.com/techind/parabolic-sar-sar}\cr #' \url{https://www.fmlabs.com/reference/SAR.htm}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:parabolic_sar}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=87} #' @keywords ts #' @examples #' #' data(ttrc) #' sar <- SAR(ttrc[,c("High","Low")]) #' "SAR" <- function(HL, accel=c(.02,.2)) { # Parabolic Stop-and-Reverse (SAR) # ---------------------------------------------- # HL = HL vector, matrix, or dataframe # accel[1] = acceleration factor # accel[2] = maximum acceleration factor # WISHLIST: # Determine signal based on DM+/DM- for first bar # If sig[1]==1, then ep[1]==high; if sig[1]==-1, then ep[1]==low # The first SAR value should be the opposite (high/low) of ep # The first acceleration factor is based on the first signal # Since I've already lost one bar, do what TA-lib does and use that bar to # determine the inital signal value. Also try to incorporate different # accel factors for long/short. # accel = c( long = c( 0.02, 0.2 ), short = long ) HL <- try.xts(HL, error=as.matrix) # Check for non-leading NAs # Leading NAs are handled in the C code naCheck(HL, 0) # called for error handling side-effect # Call C routine sar <- .Call(C_sar, HL[,1], HL[,2], accel) colnames(sar) <- "sar" reclass( sar, HL ) } ================================================ FILE: R/SNR.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2016 Peter Carl, Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Signal to Noise Ratio #' #' The n-day SNR for a given market is calculated by taking the absolute #' price change over an n-day period and dividing it by the average #' n-day volatility. #' #' \deqn{SNR_n = \frac{|C_t - C_{t-n}|}{ATR_n} #' }{SNR = abs(Cl - lag(Cl,n)) / ATR(HLC, n)$atr} #' #' Using average true range as the volatility measure captures more of the #' intraday and overnight volatility in a way that a measurement of #' Close-to-Close price change does not. #' #' The interpretation is then relatively intuitive: an SNR value of five #' indicates that the market has moved five times the volatility (average true #' range) over the given look-back period. #' #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. #' @param n Number of periods for moving average. #' @param ... Other arguments to be passed to \code{\link{ATR}}. #' @return A object of the same class as HLC or a matrix (if try.xts fails) #' containing the signal to noise ratio. #' @author Peter Carl #' @references Skeggs, James and Hill, Alex (2015). Back in Black Part 2: The #' Opportunity Set for Trend Following. #' SNR <- function(HLC, n, ...) { HLC <- try.xts(HLC, error=as.matrix) snr <- abs(HLC[,3] - lag.xts(HLC[,3], n)) / ATR(HLC, n, ...)[,"atr"] return(reclass(snr, HLC)) } ================================================ FILE: R/TDI.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Trend Detection Index #' #' The Trend Detection Index (TDI) attempts to identify starting and ending #' trends. Developed by M. H. Pee. #' #' The TDI is the (1) absolute value of the \code{n}-day sum of the \code{n}-day #' momentum, minus the quantity of (2) \code{multiple}*\code{n}-day sum of the #' absolute value of the \code{n}-day momentum, minus (3) \code{n}-day sum of #' the absolute value of the \code{n}-day momentum. #' #' I.e. TDI = (1) - [ (2) - (3) ] #' #' The direction indicator is the sum of the \code{n}-day momentum over the last #' \code{n} days. #' #' See URL in references section for further details. #' #' @param price Price series that is coercible to xts or matrix. #' @param n Number of periods to use. #' @param multiple Multiple used to calculate (2). #' @return A object of the same class as \code{price} or a matrix (if #' \code{try.xts} fails) containing the columns: #' \describe{ #' \item{ tdi }{ The Trend Detection Index. } #' \item{ di }{ The Direction Indicator. } #' } #' @note Positive/negative TDI values signal a trend/consolidation. A positive/ #' negative direction indicator signals a up/down trend. I.e. buy if the TDI #' and the direction indicator are positive, and sell if the TDI is positive #' while the direction indicator is negative. #' @author Joshua Ulrich #' @seealso See \code{\link{aroon}}, \code{\link{CCI}}, \code{\link{ADX}}, #' \code{\link{VHF}}, \code{\link{GMMA}} for other indicators that measure trend #' direction/strength. #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://www.linnsoft.com/techind/trend-detection-index-tdi}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' tdi <- TDI(ttrc[,"Close"], n=30) #' "TDI" <- function(price, n=20, multiple=2) { # Trend Detection Index price <- try.xts(price, error=as.matrix) mom <- momentum(price, n, na.pad=TRUE) mom[is.na(mom)] <- 0 di <- runSum(mom, n) abs.di <- abs(di) abs.mom.2n <- runSum(abs(mom), n*multiple) abs.mom.1n <- runSum(abs(mom), n ) tdi <- abs.di - (abs.mom.2n - abs.mom.1n) result <- cbind( tdi,di ) colnames(result) <- c( "tdi","di" ) reclass( result, price ) } ================================================ FILE: R/TRIX.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Triple Smoothed Exponential Oscillator #' #' The TRIX indicator calculates the rate of change of a triple exponential #' moving average. Developed by Jack K. Hutson. #' #' The TRIX is calculated as follows:\cr 3MA = \code{MA}( \code{MA}( #' \code{MA}(\code{price}) ) )\cr trix = 100 * [ 3MA(t) / 3MA(t-1) - 1 ] #' #' @param price Price series that is coercible to xts or matrix. #' @param n Number of periods for moving average. #' @param nSig Number of periods for signal line moving average. #' @param maType Either: #' \enumerate{ #' \item A function or a string naming the function to be called. #' \item A \emph{list} with the first component like (1) above, and #' additional parameters specified as \emph{named} components. #' See Examples. #' } #' @param percent logical; if \code{TRUE}, the rate of change is calculated #' using the \code{ROC} function, otherwise the \code{momentum} function is #' used. #' @param \dots Other arguments to be passed to the \code{maType} function in #' case (1) above. #' @return A object of the same class as \code{price} or a vector (if #' \code{try.xts} fails) containing the TRIX values. #' @note Buy/sell signals are generated when the TRIX crosses above/below zero. #' A nine-period EMA of the TRIX is used as a default signal line. Buy/sell #' signals are generated when the TRIX crosses above/below the signal line and #' is also above/below zero. #' @author Joshua Ulrich #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://www.fmlabs.com/reference/default.htm?url=TRIX.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=114}\cr #' \url{https://www.linnsoft.com/techind/trix-triple-smoothed-exponential-oscillator}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:trix}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' trix <- TRIX(ttrc[,"Close"]) #' trix4 <- TRIX(ttrc[,"Close"], #' maType=list(list(SMA), list(EMA, wilder=TRUE), list(SMA), list(DEMA))) #' "TRIX" <- function(price, n=20, nSig=9, maType, percent=TRUE, ...) { # Triple Smoothed Exponential Oscillator # Default MA if(missing(maType)) { maType <- 'EMA' } # Case of different 'maType's for all MAs. if( is.list(maType) ) { # Make sure maType is a list of lists maTypeInfo <- sapply(maType,is.list) if( !(all(maTypeInfo) && length(maTypeInfo) == 4) ) { stop("If \'maType\' is a list, you must specify\n ", "*four* MAs (see Examples section of ?TRIX)") } # If MA function has 'n' arg, see if it's populated in maType; # if it isn't, populate it with function's formal 'n' if( !is.null( formals(maType[[1]][[1]])$n ) && is.null( maType[[1]]$n ) ) { maType[[1]]$n <- n } if( !is.null( formals(maType[[2]][[1]])$n ) && is.null( maType[[2]]$n ) ) { maType[[2]]$n <- n } if( !is.null( formals(maType[[3]][[1]])$n ) && is.null( maType[[3]]$n ) ) { maType[[3]]$n <- n } if( !is.null( formals(maType[[4]][[1]])$n ) && is.null( maType[[4]]$n ) ) { maType[[4]]$n <- nSig } mavg1 <- do.call( maType[[1]][[1]], c( list(price), maType[[1]][-1] ) ) mavg2 <- do.call( maType[[2]][[1]], c( list(mavg1), maType[[2]][-1] ) ) mavg3 <- do.call( maType[[3]][[1]], c( list(mavg2), maType[[3]][-1] ) ) } # Case of one 'maType' for all MAs. else { mavg1 <- do.call( maType, c( list(price), list(n=n, ...) ) ) mavg2 <- do.call( maType, c( list(mavg1), list(n=n, ...) ) ) mavg3 <- do.call( maType, c( list(mavg2), list(n=n, ...) ) ) } if(percent) { TRIX <- 100 * ROC(mavg3, n=1, na.pad=TRUE, type="discrete") } else { TRIX <- momentum( mavg3, n=1, na.pad=TRUE ) } if( is.list(maType) ) { signal <- do.call( maType[[4]][[1]], c( list(TRIX), maType[[4]][-1] ) ) } else { signal <- do.call( maType, c( list(TRIX), list(n=nSig, ...) ) ) } result <- cbind( TRIX, signal ) colnames(result) <- c( "TRIX", "signal" ) return( result ) } ================================================ FILE: R/TTR-package.R ================================================ #' Technical Trading Rule Composite data #' #' Historical Open, High, Low, Close, and Volume data for the periods January 2, #' 1985 to December 31, 2006. Randomly generated. #' #' These data do not represent an actual security. They are provided so #' examples do not necessitate an internet connection. #' #' @name ttrc #' @docType data #' @format The format is: \tabular{lll}{ Date: \tab Class 'Date' \tab 5480 5481 #' 5482 5485 5486 ...\cr Open: \tab num \tab 3.18 3.09 3.11 3.09 3.10 ...\cr #' High: \tab num \tab 3.18 3.15 3.12 3.12 3.12 ...\cr Low: \tab num \tab 3.08 #' 3.09 3.08 3.07 3.08 ...\cr Close: \tab num \tab 3.08 3.11 3.09 3.10 3.11 #' ...\cr Volume: \tab num \tab 1870906 3099506 2274157 2086758 2166348 ...\cr } #' @source Randomly generated. #' @keywords datasets #' @examples #' #' data(ttrc) #' plot(tail(ttrc[,"Close"],100), type="l") #' @rdname ttrc NULL #' Functions to create Technical Trading Rules (TTR) #' #' This package contains many of the most popular technical analysis functions, #' as well as functions to retrieve U.S. stock symbols, and data from Yahoo #' Finance. #' #' Users will probably be most interested in the following functions:\cr #' \code{\link{ADX}}\cr \code{\link{BBands}}\cr \code{\link{changes}}\cr #' \code{\link{MovingAverages}}\cr \code{\link{MACD}}\cr \code{\link{RSI}}\cr #' \code{\link{runFun}}\cr \code{\link{stoch}}\cr \code{\link{VWAP}}\cr #' \code{\link{WebData}}\cr #' #' @name TTR #' @aliases TTR-package #' @author Joshua Ulrich #' #' Maintainer: Joshua Ulrich #' @references The following sites were used to code/document this package:\cr #' \url{https://www.fmlabs.com/reference/default.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/}\cr #' \url{https://www.linnsoft.com/indicators}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators}\cr #' @keywords package #' @examples #' #' data(ttrc) #' #' # Bollinger Bands #' bbands <- BBands( ttrc[,c("High","Low","Close")] ) #' #' # Directional Movement Index #' adx <- ADX(ttrc[,c("High","Low","Close")]) #' #' # Moving Averages #' ema <- EMA(ttrc[,"Close"], n=20) #' sma <- SMA(ttrc[,"Close"], n=20) #' #' # MACD #' macd <- MACD( ttrc[,"Close"] ) #' #' # RSI #' rsi <- RSI(ttrc[,"Close"]) #' #' # Stochastics #' stochOsc <- stoch(ttrc[,c("High","Low","Close")]) #' #' ### Note: you must have a working internet connection #' ### for the examples below to work! #' if (interactive()) { #' # Fetch U.S. symbols from the internet #' nyseSymbols <- stockSymbols("NYSE") #' #' # Fetch Yahoo! Finance data from the internet #' ge <- getYahooData("GE", 19990404, 20050607, adjust = FALSE) #' } #' #' @rdname TTR "_PACKAGE" ================================================ FILE: R/TTRtools.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Miscellaneous Tools #' #' Various functions that may be useful in designing technical trading rules. #' #' \code{growth} calculates the growth of an investment using given prices and #' signals. #' #' \code{lags} calculates the lags of a given series. #' #' @aliases growth lags #' @param price Price series that is coercible to xts or matrix. #' @param signals Signals to use (defaults to vector of ones). Use '0' for no #' position, '1' for long position, and '-1' for short position. #' @param x Object that is coercible to xts or matrix. #' @param n Number of periods to use. #' @param \dots Further arguments to be passed from or to other methods. #' @return \code{growth} returns a vector of the growth of the investment. #' #' \code{lags} returns a matrix of lagged values of the original vector. #' #' @note In \code{growth} you can specify the number of periods and type of #' compounding to use when calculating returns of the price series via the #' \code{'\dots'} argument. #' @author Joshua Ulrich #' @keywords ts #' @rdname TTRtools "lags" <- function(x, n=1) { #.Deprecated(c("xts::lag.xts","quantmod::Lag"),"TTR") # Calculate lags of a series x <- as.matrix(x) if( is.null(colnames(x)) ) colnames(x) <- paste("V",1:NCOL(x),sep="") out <- embed(x, n+1) if(n==1) lag.names <- 1 else if(NCOL(x)==1) lag.names <- 1:n else lag.names <- rep(1:n,NCOL(x)) colnames(out) <- c( colnames(x), paste(colnames(x), sort(lag.names), sep=".") ) return( out ) } #-------------------------------------------------------------------------# #' @rdname TTRtools "growth" <- function(price, signals, ...) { # Calculate growth of $1 for a series of returns (and signals). if(missing(signals)) { signals <- rep(1,NROW(price)) } else { signals <- as.vector(signals) } price <- as.vector(price) growth <- cumprod( 1 + ROC(price, ...) * signals ) return( growth ) } #-------------------------------------------------------------------------# #' @rdname TTRtools 'naCheck' <- function(x, n=0) { # Ensure NAs are only at beginning of data. if(is.null(dim(x)[2])) { NAs <- sum(is.na(x)) if( NAs > 0 ) { if( any( is.na(x[-(1:NAs)]) ) ) stop("Series contains non-leading NAs") } } else { NAs <- sum( rowSums(is.na(x)) > 0 ) if( NAs > 0 ) { if( any( is.na(x[-(1:NAs),]) ) ) stop("Series contains non-leading NAs") } } res <- list() res$NAs <- NAs res$nonNA <- (1+NAs):NROW(x) res$beg <- n+NAs invisible(res) } ================================================ FILE: R/VHF.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Vertical Horizontal Filter #' #' The Vertical Horizontal Filter (VHF) attempts to identify starting and ending #' trends. Developed by Adam White. #' #' The VHF is calculated by subtracting the \code{n}-period lowest low from the #' \code{n}-period highest high and dividing that result by the \code{n}-period #' rolling sum of the close price changes. #' #' @param price Object that is coercible to xts or matrix and contains a Close #' price series, or a High-Low-Close price series. #' @param n Number of periods to use. #' @return A object of the same class as \code{price} or a vector (if #' \code{try.xts} fails) containing the VHF values. #' @note If Close prices are given, the function calculates the max/min using #' only those prices (the default). If HLC prices are given, the function #' calculates the max/min using the high/low prices (added for flexibility). #' @author Joshua Ulrich #' @seealso See \code{\link{aroon}}, \code{\link{CCI}}, \code{\link{ADX}}, #' \code{\link{TDI}}, \code{\link{GMMA}} for other indicators that measure trend #' direction/strength. #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=119}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' vhf.close <- VHF(ttrc[,"Close"]) #' vhf.hilow <- VHF(ttrc[,c("High","Low","Close")]) #' "VHF" <- function(price, n=28) { # Vertical Horizontal Filter price <- try.xts(price, error=as.matrix) # Calculation if price series is given if(NCOL(price)==1) { high <- price low <- price close <- price } else # Calculation if HLC series is given if(NCOL(price)==3) { high <- price[,1] low <- price[,2] close <- price[,3] } else stop("Price series must be either Close, or High-Low-Close") # Find highest max, and lowest min of price series hmax <- runMax( high, n) lmin <- runMin( low, n) denom <- abs( momentum(close, n=1, na.pad=TRUE) ) VHF <- ( hmax - lmin ) / runSum(denom, n) reclass(VHF, price) } ================================================ FILE: R/WPR.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' William's \%R #' #' William's \% R. #' #' If an High-Low-Close series is provided, the indicator is calculated using #' the high/low values. If a vector is provided, the calculation only uses that #' series. #' #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. If only a univariate series is given, it will be #' used. See details. #' @param n Number of periods to use. #' @param scale Scale the result to be between 0 and -100. #' @return A object of the same class as \code{HLC} or a vector (if #' \code{try.xts} fails) containing the William's \%R values. #' @note The William's \%R calculation is similar to stochastics' fast \%K, #' and the result of \code{WPR} is equal to \code{1-fastK}. #' #' The value for William's \%R will be 0.5 whenever the highest high and #' lowest low are the same over the last \code{n} periods. #' #' William's \%R is usually scaled to be between 0 and -100, which is not what #' \code{WPR} returns by default. Set \code{scale = TRUE} to return the result #' with the usual scaling. #' #' @author Joshua Ulrich #' @seealso See \code{\link{stoch}}. #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://www.fmlabs.com/reference/WilliamsR.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=126}\cr #' \url{https://www.linnsoft.com/techind/williams-r-wpr}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:williams_r}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' hlc <- ttrc[,c("High","Low","Close")] #' stochOsc <- stoch(hlc) #' stochWPR <- WPR(hlc) #' #' # WPR is a transformation of stochastics' fastK #' all.equal(stochWPR, 1-stochOsc[,'fastK']) # TRUE #' #' # WPR converted to the usual scaling between 0 and -100 #' scaledWPR <- WPR(hlc, scale=TRUE) #' #' plot(tail(stochOsc[,"fastK"], 100), type="l", #' main="Fast %K and Williams %R", ylab="", #' ylim=range(cbind(stochOsc, stochWPR), na.rm=TRUE) ) #' lines(tail(stochWPR, 100), col="blue") #' lines(tail(1-stochWPR, 100), col="red", lty="dashed") #' "WPR" <- function(HLC, n=14, scale=FALSE) { # William's Percent R (similar to Stochastics' fast %K) HLC <- try.xts(HLC, error=as.matrix) # Calculation if HLC series is given if(NCOL(HLC)==3) { high <- HLC[,1] low <- HLC[,2] close <- HLC[,3] } else # Calculation if price vector is given if(NCOL(HLC)==1) { high <- HLC low <- HLC close <- HLC } else stop("Price series must be either High-Low-Close, or Close") hmax <- runMax(high, n) lmin <- runMin( low, n) pctR <- (hmax - close) / (hmax - lmin) pctR[is.nan(pctR)] <- 0.5 if(isTRUE(scale)) { pctR <- -100 * pctR } reclass( pctR, HLC ) } ================================================ FILE: R/WebData.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Fetch Internet Data #' #' Get investment data from the internet. #' #' \code{getYahooData} fetches individual stock data from the Yahoo! Finance #' website. It also adjusts price for splits and dividends, and volume for #' splits. See the Warning section, and note that it is deprecated in favor #' of getSymbols in the quantmod package. #' #' \code{stockSymbols} fetches instrument symbols from the nasdaq.com website, #' and adjusts the symbols to be compatible with the Yahoo! Finance website. #' #' @aliases WebData getYahooData stockSymbols #' @param symbol Yahoo! Finance instrument symbol. #' @param start Numeric; first date of desired data, in YYYYMMDD format. #' Default is first date of series. #' @param end Numeric; last date of desired data, in YYYYMMDD format. Default #' is last date of series. #' @param freq Desired data frequency. One of \code{"daily"}, \code{"weekly"}, #' \code{"monthly"}. #' @param type Type of data to return. One of \code{"price"}, or #' \code{"split"}. \code{type="split"} will return both split and dividend #' data. #' @param adjust Logical; if \code{TRUE}, the Open, High, Low, and Close prices #' will be adjusted for dividends and splits, and Volume will be adjusted for #' dividends. #' @param quiet Logical; if \code{TRUE}, status messages will be printed to the #' console. #' @param exchange Character vector of exchange names on which desired #' instrument symbols are traded. #' @param sort.by Character vector of columns by which returned data will be #' sorted. Must be one or more of \code{"Name"}, \code{"Symbol"}, #' \code{"Market.Cap"}, or \code{"Exchange"}. #' @return \code{getYahooData} returns an xts object containing the columns: #' #' \code{stockSymbols} returns a character vector containing all the listed #' symbols for the given exchanges. #' \describe{ #' \item{ Date }{ Trade date, in CCYYMMDD format. } #' \item{ Open }{ Open price. } #' \item{ High }{ High price. } #' \item{ Low }{ Low price. } #' \item{ Close }{ Close price. } #' \item{ Volume }{ Volume. } #' } #' @note The symbols returned by \code{stockSymbols} may not be in the format #' necessary to retrieve data using \code{getYahooData}. #' #' \code{getYahooData} has only been tested on daily data. It isn't known if #' the function correctly adjusts data for any other frequency. #' @author Joshua Ulrich #' @keywords ts #' @examples #' #' ### Note: you must have a working internet #' ### connection for these examples to work! #' if (interactive()) { #' ge <- getYahooData("GE", 19990404, 20050607, adjust = FALSE) #' #' nyse.symbols <- stockSymbols("NYSE") #' } #' #' @section Warning: #' As of TTR 0.23-2, \code{getYahooData} has been patched to work with changes #' to Yahoo Finance, which also included the following changes to the raw data: #' \itemize{ #' \item The adjusted close column appears to no longer include dividend adjustments #' \item The open, high, and low columns are adjusted for splits, and #' \item The raw data may contain missing values. #' \item The raw data may contain errors. #' } #' #' As of TTR 0.24.2, \code{stockSymbols} began using data from NASDAQ's FTP #' site because the data from the original site is no longer available. This #' new file does not contain data for the columns: LastSale, MarketCap, #' IPOyear, Sector, and Industry. All the columns still appear in the results,#' but all the values in the columns are set to \code{NA}. #' #' @references #' #' \itemize{ #' \item \href{https://quant.stackexchange.com/questions/1640/where-to-download-list-of-all-common-stocks-traded-on-nyse-nasdaq-and-amex/1862}{Quant StackExchange: Download list of all stock symbols?} #' \item \href{https://www.nasdaqtrader.com/trader.aspx?id=CQSsymbolconvention}{CQS symbol convention} #' \item \href{https://web.archive.org/web/20111023221931/http://help.yahoo.com/l/us/yahoo/finance/quotes/quote-02.html}{Yahoo Finance symbol conventions} #' } #' #' @rdname WebData "stockSymbols" <- function(exchange = c("AMEX", "NASDAQ", "NYSE", "ARCA", "BATS", "IEX"), sort.by = c("Exchange", "Symbol"), quiet = FALSE) { # Many thanks to Ion Georgiadis for helpful suggestions and testing. # See "NYSE "behind the dot" or Nasdaq 5th-letter codes and other special # codes" here: # http://en.wikipedia.org/wiki/Ticker_symbol # # AMEX / NYSE Mappings (NASDAQ doesn't need transformation?): # Exchanges -> Yahoo # /WS -> -WT # /U -> -U # .[A-Z] -> NA (special notes/bonds - IG) # :[AP] -> NA (after-hours / pre-market) # ^ -> -P # / -> - # $ -> NA (NYSE Only) # ~ -> NA (NYSE Only) symbols.colnames <- c("Symbol","Name","LastSale","MarketCap","IPOyear","Sector","Industry", "Exchange", "Test.Issue", "Round.Lot.Size", "ETF", "Market.Category", "Financial.Status", "Next.Shares", "ACT.Symbol", "CQS.Symbol") exchange <- match.arg(exchange, several.ok=TRUE) sort.by <- match.arg(sort.by, symbols.colnames, several.ok=TRUE) ### nasdaqlisted.txt ##nasdaq.colnames <- ## c("Symbol", ## "Security.Name", ## "Market.Category", ## "Test.Issue", ## "Financial.Status", ## "Round.Lot.Size", ## "ETF", ## "NextShares") .market.category <- c(Q = "NASDAQ Global Select MarketSM", G = "NASDAQ Global MarketSM", S = "NASDAQ Capital Market") ### otherlisted.txt ##other.colnames <- ## c("ACT.Symbol", ## "Security.Name", ## "Exchange", ## "CQS.Symbol", ## "ETF", ## "Round.Lot.Size", ## "Test.Issue", ## "NASDAQ.Symbol") .exchange <- c(A = "AMEX", N = "NYSE", P = "ARCA", Z = "BATS", V = "IEX") .financial.status <- c(D = "Deficient", E = "Delinquent", Q = "Bankrupt", N = "Normal (Default)", G = "Deficient and Bankrupt", H = "Deficient and Delinquent", J = "Delinquent and Bankrupt", K = "Deficient, Delinquent, and Bankrupt") tmp <- tempfile() base.url <- "ftp://ftp.nasdaqtrader.com/SymbolDirectory/" nasdaq.url <- paste0(base.url, "nasdaqlisted.txt") other.url <- paste0(base.url, "otherlisted.txt") nasdaq <- NULL if ("NASDAQ" %in% exchange) { if (!quiet) { message("Fetching NASDAQ symbols...") flush.console() } curl::curl_download(nasdaq.url, destfile = tmp) nasdaq <- read.table(tmp, header = TRUE, sep = "|", quote = "", fill = TRUE, na.strings = NULL) # add symbols columns not in file nasdaq$Name <- nasdaq$Security.Name nasdaq$Exchange <- "NASDAQ" nasdaq[, setdiff(symbols.colnames, colnames(nasdaq))] <- NA # order columns nasdaq <- nasdaq[, symbols.colnames] # convert market category code to name nasdaq$Market.Category <- .market.category[nasdaq$Market.Category] # convert financial status code to name nasdaq$Financial.Status <- .financial.status[nasdaq$Financial.Status] } other <- NULL if (length(exchange) > 1L) { if (!quiet) { message("Fetching non-NASDAQ symbols...") flush.console() } curl::curl_download(other.url, destfile = tmp) other <- read.table(tmp, header = TRUE, sep = "|", quote = "", fill = TRUE, na.strings = NULL) # remove last row (File creation time) other <- other[-nrow(other),] # add symbols columns not in file other$Name <- other$Security.Name other$Symbol <- other$NASDAQ.Symbol other[, setdiff(symbols.colnames, colnames(other))] <- NA # convert exchange code to name other$Exchange <- .exchange[other$Exchange] # order columns other <- other[, symbols.colnames] } # Append data from all exchanges symbols <- rbind(nasdaq, other) # Convert symbol from NASDAQ to Yahoo format # symbols[grep("[-.*$+!@%^=#].?$", symbols$NASDAQ.Symbol),c("Symbol", "NASDAQ.Symbol")] symbols$NASDAQ.Symbol <- symbols$Symbol # preferreds symbols$Symbol <- sub("-(.?)$", "-P\\1", symbols$Symbol) # classes symbols$Symbol <- sub("\\.(.?)$", "-\\1", symbols$Symbol) # warrants symbols$Symbol <- sub("\\+(.?)$", "-WT\\1", symbols$Symbol) # units symbols$Symbol <- sub("\\=$", "-UN", symbols$Symbol) # rights symbols$Symbol <- sub("\\^$", "-R", symbols$Symbol) # convert ETF and Test.Issue to logical symbols$ETF <- ("Y" == symbols$ETF) symbols$Test.Issue <- ("Y" == symbols$Test.Issue) # Sort symbols <- symbols[do.call("order", symbols[,sort.by]),] # Pretty rownames rownames(symbols) <- NULL return(symbols) } #-------------------------------------------------------------------------# #' @rdname WebData "getYahooData" <- function(symbol, start, end, freq="daily", type="price", adjust=TRUE, quiet=FALSE) { warn.Deprecated <- function() { .Deprecated("quantmod::getSymbols", package = "TTR", paste("TTR::getYahooData is deprecated and will be removed in a", "future release.\nPlease use quantmod::getSymbols instead."), old = "getYahooData") } callingFun <- sys.call(-1L)[[1]] if(is.null(callingFun)) { # Called from top level warn.Deprecated() } else { if(is.call(callingFun) && any(deparse(callingFun[[1]]) == c("::", ":::"))) { if("getYahooData" != as.character(callingFun[[3]])) warn.Deprecated() } else { if("getYahooData" != deparse(callingFun)) warn.Deprecated() } } # Thank you to Giorgio Beltrame for the URL to download dividends _and_ # splits, and for his correct adjustment procedure. # Many thanks to Ion Georgiadis for helpful suggestions and testing. # symbol: Character, instrument symbol # start: Numeric, starting date, in ISO-8601 format as ccyymmdd (default # is series' first date) # end: Numeric, ending date, in ISO-8601 format as ccyymmdd (default is today) # freq: Character, frequency of data # either 'daily', 'weekly', 'monthly' # type: Character, either 'price' or 'split' # adjust: Logical, adjusts the Open, High, Low, and Close prices for # dividends and splits, and adjusts Volume for dividends. # # http://help.yahoo.com/l/us/yahoo/finance/quotes/quote-12.html # http://ichart.finance.yahoo.com/x?s=MSFT&g=d&y=0&z=30000 # # Requires R-2.4.1 # Check dates if (missing(start)) { beg <- .dateToUNIX(as.Date("1900-01-01")) } else { beg <- .dateToUNIX(as.Date(as.character(start), "%Y%m%d")) } if (missing(end)) { end <- .dateToUNIX(Sys.Date()) } else { end <- .dateToUNIX(as.Date(as.character(end), "%Y%m%d")) } if( beg > end ) stop("Start date must be before end date.") if (beg > .dateToUNIX(Sys.Date())) stop("Start date is after today's date.") # Get frequency and type parameters intervals <- c(daily = "1d", weekly = "1wk", monthly = "1mo") freq <- match.arg( freq, names(intervals) ) interval <- intervals[freq] type <- match.arg( type, c("price","split") ) if(type!="price") { if(freq!="daily" && !quiet) message("Only freq=\"daily\" data available for type=\"split\".\n", "Setting freq=\"daily\"...") } tmp <- tempfile() on.exit(unlink(tmp), add = TRUE) flush.console() if(type=="price") { if(adjust) { if(freq=="daily") { # Get price, dividend, and split data from 'beg' to present ohlc <- getYahooData(symbol, start, freq="daily", type="price", adjust=FALSE, quiet=TRUE) divspl <- getYahooData(symbol, start, freq="daily", type="split", adjust=FALSE, quiet=TRUE) ohlc <- merge(ohlc, divspl, all=TRUE) # If there are no div/spl, then ohlc is a zero-width xts object if(NROW(divspl) != 0) { adj <- adjRatios(ohlc[,'Split'],ohlc[,'Div'],ohlc[,'Close']) s.ratio <- adj[,1] d.ratio <- adj[,2] # Adjust OHLC and volume cn <- colnames(ohlc) ohlc <- cbind(ohlc,ohlc[,'Close']) colnames(ohlc) <- c(cn,'Unadj.Close') #ohlc[,'Unadj.Close'] <- ohlc[,'Close'] ohlc[,'Open'] <- ohlc[,'Open'] * d.ratio * s.ratio ohlc[,'High'] <- ohlc[,'High'] * d.ratio * s.ratio ohlc[,'Low'] <- ohlc[,'Low'] * d.ratio * s.ratio ohlc[,'Close'] <- ohlc[,'Close'] * d.ratio * s.ratio ohlc[,'Volume'] <- ohlc[,'Volume'] * ( 1 / d.ratio ) # Order columns #ohlc <- ohlc[,c("Date","Open","High","Low","Close","Volume", ohlc <- ohlc[,c("Open","High","Low","Close","Volume", "Unadj.Close","Div","Split","Adj.Div")] } } else stop("Only freq=\"daily\" adjusted data is currently supported.") # For other frequencies, get daily data and use a routine to # aggregate to desired frequency. } else { handle <- .getHandle() # Construct URL for 'beg' to 'end' url <- .yahooURL(symbol, beg, end, interval, "history", handle) # Fetch data curl::curl_download(url, destfile=tmp, quiet=quiet, handle=handle$ch) # Read data ohlc <- read.csv(tmp, na.strings="null") # Re-order and set column names cnames <- c("Date", "Open", "High", "Low", "Close", "Volume", "Adjusted") corder <- pmatch(substr(cnames, 1, 3), colnames(ohlc)) ohlc <- ohlc[,corder] colnames(ohlc) <- cnames ohlc[,'Adjusted'] <- NULL ohlc <- ohlc[order(ohlc[,"Date"]),] ohlc <- xts(ohlc[,-1], as.Date(as.character(ohlc[,1]))) } } else { if(!quiet) message("Unadjusted and adjusted dividend data are always returned.") handle <- .getHandle() # Split data url <- .yahooURL(symbol, beg, end, "1d", "split", handle) curl::curl_download(url, destfile=tmp, quiet=quiet, handle=handle$ch) spl <- read.csv(tmp, as.is=TRUE) if(NROW(spl)==0) { spl <- NA } else { spl$V3 <- 1 / sapply(parse(text=spl[,2]), eval) spl <- xts(spl$V3, as.Date(spl[,1], "%Y-%m-%d")) colnames(spl) <- NULL } # Dividend data url <- .yahooURL(symbol, beg, end, "1d", "div", handle) curl::curl_download(url, destfile=tmp, quiet=quiet, handle=handle$ch) div <- read.csv(tmp, as.is=TRUE) div <- xts(div[,2],as.Date(div[,1])) colnames(div) <- NULL ohlc <- merge(Adj.Div = div, Split = spl) # Return (empty) data if(NROW(ohlc)==0) return(ohlc) if( all(is.na(ohlc[,'Split'])) ) { s.ratio <- rep(1,NROW(ohlc)) } else { s.ratio <- adjRatios(splits=ohlc[,'Split'])[,1] } # Un-adjust dividends for Splits ohlc <- cbind(ohlc,ohlc[,"Adj.Div"] * ( 1 / s.ratio )) colnames(ohlc)[3] <- "Div" ohlc[,'Split'] <- as.numeric(ohlc[,'Split']) # Order data columns ohlc <- ohlc[,c("Div","Split","Adj.Div")] } # Only return requested data dateRange <- paste(as.Date(.POSIXct(beg, tz = "UTC")), as.Date(.POSIXct(end, tz = "UTC")), sep = "/") ohlc <- ohlc[dateRange] ### Check to see if supplied dates occur in data set # if( max(ohlc[,'Date']) != as.Date(end) ) { # if(!quiet) message("End date out of range, " , max(ohlc[,'Date']), " is last available date.") # } # if( min(ohlc[,'Date']) != as.Date(beg) ) { # if(!quiet) message("Start date out of range, ", min(ohlc[,'Date']), " is first available date.") # } return(ohlc) } .getHandle <- function(force.new = FALSE) { h <- if (exists("_handle_", .env)) get("_handle_", .env) else NULL if (is.null(h) || force.new) { # create 'h' if it doesn't exist yet if (!force.new) { h <- list() } # establish session new.session <- function(h) { tmp <- tempfile() on.exit(unlink(tmp)) for (i in 1:5) { h <- curl::new_handle() # random query to avoid cache ru <- paste(sample(c(letters, 0:9), 4), collapse = "") cu <- paste0("https://finance.yahoo.com?", ru) curl::curl_download(cu, tmp, handle = h) if (NROW(curl::handle_cookies(h)) > 0) break; Sys.sleep(0.1) } if (NROW(curl::handle_cookies(h)) == 0) stop("Could not establish session after 5 attempts.") return(h) } h$ch <- new.session() n <- if (unclass(Sys.time()) %% 1L >= 0.5) 1L else 2L query.srv <- paste0("https://query", n, ".finance.yahoo.com/", "v1/test/getcrumb") cres <- curl::curl_fetch_memory(query.srv, handle = h$ch) h$cb <- rawToChar(cres$content) assign("_handle_", h, .env) } return(h) } .yahooURL <- function(symbol, from, to, period, type, handle) { p <- match.arg(period, c("1d", "1wk", "1mo")) e <- match.arg(type, c("history", "div", "split")) n <- if (unclass(Sys.time()) %% 1L >= 0.5) 1L else 2L u <- paste0("https://query", n, ".finance.yahoo.com/v7/finance/download/", symbol, "?period1=", from, "&period2=", to, "&interval=", p, "&events=", e, "&crumb=", handle$cb) return(u) } .dateToUNIX <- function(Date) { posixct <- as.POSIXct(as.Date(Date, origin = "1970-01-01")) trunc(as.numeric(posixct)) } ================================================ FILE: R/ZigZag.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Zig Zag #' #' Zig Zag higlights trends by removing price changes smaller than \code{change} #' and interpolating lines between the extreme points. #' #' The Zig Zag is non-predictive. The purpose of the Zig Zag is filter noise #' and make chart patterns clearer. It's more a visual tool than an indicator. #' #' @aliases ZigZag zigzag #' @param HL Object that is coercible to xts or matrix and contains either a #' High-Low price series, or a Close price series. #' @param change Minimum price movement, either in dollars or percent (see #' \code{percent}). #' @param percent Use percentage or dollar change? #' @param retrace Is \code{change} a retracement of the previous move, or an #' absolute change from peak to trough? #' @param lastExtreme If the extreme price is the same over multiple periods, #' should the extreme price be the first or last observation? #' @return A object of the same class as \code{HL} or a vector (if #' \code{try.xts} fails) containing the Zig Zag indicator. #' @note If High-Low prices are given, the function calculates the max/min using #' the high/low prices. Otherwise the function calculates the max/min of the #' single series. #' @section Warning: The last value of the ZigZag indicator is unstable (i.e. #' unknown) until the turning point actually occurs. Therefore this indicator #' isn't well-suited for use for systematic trading strategies. #' @author Joshua Ulrich #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://www.fmlabs.com/reference/default.htm?url=ZigZag.htm}\cr #' \url{https://www.linnsoft.com/techind/zig-zag-indicator-zig-zzo}\cr #' \url{https://www.linnsoft.com/techind/zig-zag-oscillator-indicator-zzo}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=127}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:zigzag}\cr #' @keywords ts #' @examples #' #' ## Get Data and Indicator ## #' data(ttrc) #' zz <- ZigZag( ttrc[,c("High", "Low")], change=20 ) #' "ZigZag" <- function( HL, change=10, percent=TRUE, retrace=FALSE, lastExtreme=TRUE ) { # Zig Zag Indicator # Adapted from Alberto Santini's code HL <- try.xts(HL, error=as.matrix) HL.na <- naCheck(HL,0) # Calculation if HL series is given if(NCOL(HL)==2) { high <- HL[HL.na$nonNA,1] low <- HL[HL.na$nonNA,2] } else # Calculation if price vector is given if(NCOL(HL.na)==1) { high <- HL[HL.na$nonNA] low <- HL[HL.na$nonNA] } else stop("Price series must be either High-Low, or Univariate") # Call C routine zz <- .Call(C_ttr_zigzag, as.numeric(high), as.numeric(low), as.numeric(change), as.logical(percent), as.logical(retrace), as.logical(lastExtreme)) # Interpolate results zz <- na.approx(zz, na.rm = FALSE) # Prepend NAs from original data zz <- c( rep( NA, HL.na$NAs ), zz ) reclass( zz, HL ) } ================================================ FILE: R/adjRatios.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Split and dividend adjustment ratios #' #' Create split and dividend adjustment ratio vectors. #' #' @aliases adjRatios adjust #' @param splits Split series that is coercible to xts. #' @param dividends Dividend series that is coercible to xts. #' @param close Close price series that is coercible to xts. #' @return A xts object containing the columns: #' \describe{ #' \item{ Split }{ The split adjustment ratio. } #' \item{ Div }{ The dividend adjustment ratio. } #' } #' @details #' \itemize{ #' \item If only \code{splits} is provided, the resulting object will #' only have as many observations as \code{splits}. #' \item If \code{splits} and \code{close} are provided, the resulting #' object will have as many observations as \code{max(NROW(splits), #' NROW(close))}. #' \item \code{close} is required if \code{dividends} is provided. #' } #' #' @author Joshua Ulrich #' @keywords ts 'adjRatios' <- function(splits, dividends, close) { if( !missing(dividends) && missing(close) ) stop('"close" must be specified to adjust dividends') # Really need a better error message if as.xts fails... seriously if(missing(close) || all(is.na(close)) || NROW(close)==0) { close <- NA } else { if(NCOL(close)!=1) stop('"close" must be univariate') close <- try.xts(close, error=stop('"as.xts(close)" failed')) } if(missing(splits) || all(is.na(splits)) || NROW(splits)==0) { splits <- NA } else { if(NCOL(splits)!=1) stop('"splits" must be univariate') splits <- try.xts(splits, error=stop('"as.xts(splits)" failed')) } if(missing(dividends) || all(is.na(dividends)) || NROW(dividends)==0) { dividends <- NA } else { if(NCOL(dividends)!=1) stop('"dividends" must be univariate') dividends <- try.xts(dividends, error=stop('"as.xts(dividends)" failed')) } obj <- merge.xts(close,splits,dividends) if(!isTRUE(is.na(close))) { obj <- obj[!is.na(obj[,1]),] # drop rows missing close prices } adj <- .Call(C_adjRatios, obj[,2], obj[,3], obj[,1]) adj <- xts(cbind(adj[[1]],adj[[2]]),index(obj)) colnames(adj) <- c('Split','Div') return(adj) } ================================================ FILE: R/aroon.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Aroon #' #' The Aroon indicator attempts to identify starting trends. The indicator #' consists of up and down lines, which measure how long it has been since the #' highest high/lowest low has occurred in the last \code{n} periods. Developed #' by Tushar Chande in 1995. #' #' Aroon up (down) is the elapsed time, expressed as a percentage, between today #' and the highest (lowest) price in the last \code{n} periods. If today's #' price is a new high (low) Aroon up (down) will be 100. Each subsequent period #' without another new high (low) causes Aroon up (down) to decrease by (1 / #' \code{n}) x 100. #' #' @param HL Object that is coercible to xts or matrix and contains either a #' High-Low price series, or a Close price series. #' @param n Number of periods to use in the calculation. #' @return A object of the same class as \code{HL} or a matrix (if #' \code{try.xts} fails) containing the columns: #' \describe{ #' \item{ aroonUp }{ The Aroon up indicator. } #' \item{ aroonDn }{ The Aroon down indicator. } #' \item{ oscillator }{ The Aroon oscillator (\code{aroonUp - aroonDn}). } #' } #' @note If High-Low prices are given, the function calculates the max/min using #' the high/low prices. Otherwise the function calculates the max/min of the #' single series. #' #' Up (down) trends are indicated when the aroonUp(Dn) is between 70 and 100. #' Strong trends are indicated when when the aroonUp(Dn) is above 70 while the #' aroonDn(Up) is below 30. Also, crossovers may be useful. #' @author Joshua Ulrich #' @seealso See \code{\link{CCI}}, \code{\link{ADX}}, \code{\link{TDI}}, #' \code{\link{VHF}}, \code{\link{GMMA}} for other indicators that measure trend #' direction/strength. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.fmlabs.com/reference/Aroon.htm}\cr #' \url{https://www.fmlabs.com/reference/AroonOscillator.htm}\cr #' \url{https://www.linnsoft.com/techind/aroon-arn}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:aroon}\cr #' @keywords ts #' @examples #' #' ## Get Data and Indicator ## #' data(ttrc) #' trend <- aroon( ttrc[,c("High", "Low")], n=20 ) #' "aroon" <- function(HL, n=20) { # Aroon up, down, and oscillator. HL <- try.xts(HL, error=as.matrix) # Calculation if price vector is given if(NCOL(HL)==1) { high <- HL low <- HL } else # Calculation if HL series is given if(NCOL(HL)==2) { high <- HL[,1] low <- HL[,2] } else stop("Price series must be either High-Low, or Close") # Calculate Aroon UP and DOWN aroonUp <- .Call(C_aroon_max, high, n) aroonDn <- .Call(C_aroon_max, -low, n) oscillator <- aroonUp - aroonDn result <- cbind( aroonUp, aroonDn, oscillator ) colnames(result) <- c( "aroonUp", "aroonDn", "oscillator" ) reclass( result, HL ) } ================================================ FILE: R/bollingerBands.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Bollinger Bands #' #' Bollinger Bands are a way to compare a security's volatility and price levels #' over a period of time. Developed by John Bollinger. #' #' Bollinger Bands consist of three lines: #' #' The middle band is generally a 20-period SMA of the typical price ([high + #' low + close]/3). The upper and lower bands are \code{sd} standard deviations #' (generally 2) above and below the MA. #' #' The middle band is usually calculated using the typical price, but if a #' univariate series (e.g. Close, Weighted Close, Median Price, etc.) is #' provided, it will be used instead. #' #' @aliases bollingerBands BBands #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. If only a univariate series is given, it will be #' used. See details. #' @param n Number of periods for moving average. #' @param maType A function or a string naming the function to be called. #' @param sd The number of standard deviations to use. #' @param \dots Other arguments to be passed to the \code{maType} function. #' @return A object of the same class as \code{HLC} or a matrix (if #' \code{try.xts} fails) containing the columns: #' \describe{ #' \item{ dn }{ The lower Bollinger Band. } #' \item{ mavg }{ The middle Moving Average (see notes). } #' \item{ up }{ The upper Bollinger Band. } #' \item{ pctB }{ The \%B calculation. } #' } #' @note Using any moving average other than SMA will result in inconsistencies #' between the moving average calculation and the standard deviation #' calculation. Since, by definition, a rolling standard deviation uses a #' simple moving average. #' @author Joshua Ulrich #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.fmlabs.com/reference/Bollinger.htm}\cr #' \url{https://www.fmlabs.com/reference/BollingerWidth.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=36}\cr #' \url{https://www.linnsoft.com/techind/bollinger-bands}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_band_width}\cr #' @keywords ts #' @examples #' #' ## The examples below show the differences between using a #' ## High-Low-Close series, and just a close series when #' ## calculating Bollinger Bands. #' data(ttrc) #' bbands.HLC <- BBands( ttrc[,c("High","Low","Close")] ) #' bbands.close <- BBands( ttrc[,"Close"] ) #' @rdname bollingerBands "BBands" <- function(HLC, n=20, maType, sd=2, ...) { # Bollinger Bands HLC <- try.xts(HLC, error=as.matrix) if(NCOL(HLC)==3) { if(is.xts(HLC)) { xa <- xcoredata(HLC) HLC <- xts(apply(HLC, 1, mean),index(HLC)) xcoredata(HLC) <- xa } else { HLC <- apply(HLC, 1, mean) } } else if(NCOL(HLC)!=1) { stop("Price series must be either High-Low-Close, or Close/univariate.") } maArgs <- list(n=n, ...) # Default MA if(missing(maType)) { maType <- 'SMA' } mavg <- do.call( maType, c( list(HLC), maArgs ) ) # Calculate standard deviation by hand to incorporate various MAs sdev <- runSD(HLC, n, sample=FALSE) up <- mavg + sd * sdev dn <- mavg - sd * sdev pctB <- (HLC - dn) / (up - dn) res <- cbind(dn, mavg, up, pctB) colnames(res) <- c("dn", "mavg", "up", "pctB") reclass(res, HLC) } ================================================ FILE: R/chaikinAD.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Chaikin Accumulation / Distribution #' #' The Chaikin Accumulation / Distribution (AD) line is a measure of the money #' flowing into or out of a security. It is similar to On Balance Volume (OBV). #' Developed by Marc Chaikin. #' #' The AD line is similar to OBV; the difference is that OBV sums volume #' multiplied by +/- 1 if the close is higher/lower than the previous close, #' while the AD line multiplies volume by the close location value (CLV). #' #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. #' @param volume Vector or matrix of volume observations corresponding to the #' \code{HLC} object. #' @return A object of the same class as \code{HLC} and \code{volume} or a #' vector (if \code{try.xts} fails) containing the accumulation / distribution #' values. #' @note The Accumulation/Distribution Line is interpreted by looking for a #' divergence in the direction of the indicator relative to price. #' @author Joshua Ulrich #' @seealso See \code{\link{OBV}}, and \code{\link{CLV}}. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.fmlabs.com/reference/AccumDist.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=27}\cr #' \url{https://www.linnsoft.com/techind/accumulation-distribution}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' ad <- chaikinAD(ttrc[,c("High","Low","Close")], ttrc[,"Volume"]) #' "chaikinAD" <- function(HLC, volume) { # Chaikin Accumulation / Distribution HLC <- try.xts(HLC, error=as.matrix) volume <- try.xts(volume, error=as.matrix) if(!(is.xts(HLC) && is.xts(volume))) { HLC <- as.matrix(HLC) volume <- as.matrix(volume) } ad <- CLV(HLC) * volume ad.na <- naCheck(ad) ad <- cumsum( ad[ad.na$nonNA] ) ad <- c( rep( NA, ad.na$NAs ), ad ) reclass(ad, HLC) } ================================================ FILE: R/chaikinVolatility.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Chaikin Volatility #' #' Chaikin Volatility measures the rate of change of the security's trading #' range. Developed by Marc Chaikin. #' #' The Chaikin Volatility indicator defines volatility as an increase in the #' difference between the high and low. #' #' @param HL Object that is coercible to xts or matrix and contains High-Low #' prices. #' @param n Number of periods for moving average. #' @param maType A function or a string naming the function to be called. #' @param \dots Other arguments to be passed to the \code{maType} function. #' @return A object of the same class as \code{HL} or a vector (if #' \code{try.xts} fails) containing the Chaikin Volatility values. #' @note A rapid increase in Chaikin Volatility indicates an approaching bottom. #' A slow decrease in Chaikin Volatility indicates an approaching top. #' @author Joshua Ulrich #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. See \code{\link{TR}} for another #' volatility measure. #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://www.fmlabs.com/reference/ChaikinVolatility.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=120}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' volatility <- chaikinVolatility(ttrc[,c("High","Low")]) #' "chaikinVolatility" <- function(HL, n=10, maType, ...) { # Chaikin Volatility HL <- try.xts(HL, error=as.matrix) maArgs <- list(n=n, ...) # Default MA if(missing(maType)) { maType <- 'EMA' } mavg <- do.call( maType, c( list(HL[,1]-HL[,2]), maArgs ) ) volatility <- ROC( mavg, n, type="discrete" ) reclass(volatility, HL) } ================================================ FILE: R/changes.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Rate of Change / Momentum #' #' Calculate the (rate of) change of a series over \code{n} periods. #' #' The ROC indicator provides the percentage difference of a series over two #' observations, while the momentum indicator simply provides the difference. #' #' @aliases changes ROC momentum #' @param x Price, volume, etc. series that is coercible to xts or matrix. #' @param n Number of periods to use. #' @param type Compounding type; either \code{"continuous"} (the default) or #' \code{"discrete"}. #' @param na.pad Should periods prior to \code{n} be appended? Default is #' \code{TRUE}. #' @return A object of the same class as \code{x} or a vector (if \code{try.xts} #' fails) containing the rate-of-change (or return) values for \code{ROC} or a #' vector containing the differenced price series for \code{momentum}. #' @author Joshua Ulrich #' @keywords ts #' @examples #' #' data(ttrc) #' roc <- ROC(ttrc[,"Close"]) #' mom <- momentum(ttrc[,"Close"]) #' @rdname changes "ROC" <- function(x, n=1, type=c("continuous","discrete"), na.pad=TRUE) { # Rate of Change x <- try.xts(x, error=as.matrix) type <- match.arg(type) if(is.xts(x)) { if(type=="discrete") { roc <- x / lag.xts(x,n,na.pad=na.pad) - 1 } # Continuous change if(type=="continuous") { roc <- diff(log(x),n,na.pad=na.pad) } # Convert back to original class reclass(roc, x) } else { NAs <- NULL if(na.pad) { NAs <- rep(NA,n) } # Discrete changes if(type=="discrete") { roc <- c( NAs, x[(n+1):NROW(x)] / x[1:(NROW(x)-n)] - 1 ) } # Continuous changes if(type=="continuous") { roc <- c( NAs, diff(log(x),n) ) } return(roc) } } #-------------------------------------------------------------------------# #' @rdname changes "momentum" <- function(x, n=1, na.pad=TRUE) { # Momentum # http://www.fmlabs.com/reference/Momentum.htm # https://www.metastock.com/Customer/Resources/TAAZ/?p=95 # https://www.linnsoft.com/tour/techind/momentum.htm x <- try.xts(x, error=as.matrix) if(is.xts(x)) { mom <- diff(x,n,na.pad=na.pad) } else { NAs <- NULL if(na.pad) { NAs <- rep(NA,n) } mom <- c( NAs, diff(x, n) ) } reclass(mom,x) } ================================================ FILE: R/keltnerChannels.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2020 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Keltner Channels #' #' Keltner Channels are volatility-based envelopes set above and below a moving #' average. This indicator is similar to Bollinger Bands, but Keltner Channels #' use the Average True Range (ATR) to set channel distance. #' #' Keltner Channels are a trend following indicator, and can also be used to #' identify overbought and oversold levels when there is no trend. #' #' Chester Keltner is credited with the original version of Keltner Channels in #' his 1960 book. Linda Bradford Raschke introduced the newer version of #' Keltner Channels in the 1980s. #' #' @aliases keltnerChannels #' #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. If only a univariate series is given, it will be used. #' See details. #' @param n Number of periods for moving average. #' @param maType A function or a string naming the function to be called. #' @param atr The number of average true range distances to apply. #' @param ... Other arguments to be passed to the maType function. #' #' @section Details : Keltner Channels consist of three lines: #' The middle band is generally a 20-period EMA of the typical price #' ([high + low + close]/3). The upper and lower bands are multiples of average #' true range (usually 2) above and below the MA. #' #' The middle band is usually calculated using the typical price, but if a #' univariate series (e.g. Close, Weighted Close, Median Price, etc.) is #' provided, it will be used instead. #' #' @return A object of the same class as \code{HLC} or a matrix (if #' \code{try.xts} fails) containing the columns: #' \describe{ #' \item{SMA}{ Simple moving average. } #' \item{EMA}{ Exponential moving average. } #' } #' #' \item{dn}{ The lower Keltner Channel. } #' \item{mavg}{ The middle moving average. } #' \item{up}{ The upper Keltner Channel. } #' #' @author Nick Procyk, Joshua Ulrich #' #' References #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels}\cr #' \url{https://www.linnsoft.com/techind/keltner-channels-keltu-keltd}\cr #' \url{https://www.investopedia.com/terms/k/keltnerchannel.asp}\cr #' #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. #' #' @examples #' #' data(ttrc) #' kc <- keltnerChannels(ttrc[,c("High","Low","Close")]) #' #' @keywords ts #' @rdname keltnerChannels keltnerChannels <- function (HLC, n = 20, maType, atr = 2, ...) { atrHLC <- HLC HLC <- try.xts(HLC, error = as.matrix) if (NCOL(HLC) == 3) { if (is.xts(HLC)) { xa <- xcoredata(HLC) HLC <- xts(apply(HLC, 1, mean), index(HLC)) xcoredata(HLC) <- xa } else { HLC <- apply(HLC, 1, mean) } } else if (NCOL(HLC) != 1) { stop("Price series must be either High-Low-Close, or Close/univariate.") } maArgs <- list(n = n, ...) if (missing(maType)) { maType <- "EMA" } mavg <- do.call(maType, c(list(HLC), maArgs)) avgtruerange <- ATR(atrHLC, n = n) up <- mavg + atr * avgtruerange[,2] dn <- mavg - atr * avgtruerange[,2] res <- cbind(dn, mavg, up) colnames(res) <- c("dn", "mavg", "up") reclass(res, HLC) } ================================================ FILE: R/percentRank.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Percent Rank over a Moving Window #' #' This function computes a running/rolling percentage rank. #' #' The computation for a percentage rank can vary depending on the weight given #' to values in the window that are equal to the value being ranked. This weight #' can be set using the \code{exact.multiplier} argument which defaults to 0.5. #' #' \code{exact.multiplier = 0} scores equal values in the lookback window as #' always being greater than the value being ranked. \code{exact.multiplier = 1} #' scores equal values as being below the value being ranked. Any multiplier #' between 0 and 1 counts that proportion of the equal values as being below #' the value being ranked. #' #' The value of \code{exact.multiplier} has the most impact when the window is #' relatively small or when the number of discrete values in the window is #' small. For non-repeating values, changing \code{exact.multiplier = 0} to #' \code{exact.multiplier = 1} for a window of size \code{N} will shift the #' resulting percentile rankings by \code{1/N}. It is equivalent to changing #' the question from, "how many values are < the value" to "how many values #' are <= the value". #' #' @aliases runPercentRank percentRank PercentRank #' @param x Object coercible to xts or matrix. #' @param n Number of periods to use in the window or, if #' \code{cumulative=TRUE}, the number of observations to use before the first #' result is returned. Must be between 1 and \code{nrow(x)}, inclusive. #' @param cumulative Logical, use from-inception calculation? #' @param exact.multiplier The weight applied to identical values in the window. #' Must be between 0 and 1, inclusive. See details. #' #' @return A object of percent ranks over a n-period moving window of the same #' class as \code{x} and \code{y} or a vector (if \code{try.xts} fails). #' #' @note This computation is different from the one used in Microsoft Excel's #' \code{PERCENTRANK} formula. Excel's computation is rather strange and gives #' inconsistent results as it uses interpolation to rank values that are not #' found within the lookback window. #' #' @author Charlie Friedemann #' #' @references The following site(s) were used to code/document this #' indicator:\cr \url{https://en.wikipedia.org/wiki/Percentile_rank}\cr #' #' @keywords ts runPercentRank <- function(x, n=260, cumulative = FALSE, exact.multiplier = 0.5) { x <- try.xts(x, error = as.matrix) if (n < 1 || n > NROW(x)) stop(sprintf("n = %d is outside valid range: [1, %d]", n, NROW(x))) if (exact.multiplier < 0 || exact.multiplier > 1) stop(sprintf("exact.multiplier = %d is outside valid range: [0, 1]", exact.multiplier)) NAs <- sum(is.na(x)) if (NAs > 0) { if (any(is.na(x[-(1:NAs)]))) stop("Series contains non-leading NAs") } if (!isTRUE(cumulative) && identical(as.integer(n), 1L)) { result <- double(NROW(x)) result[] <- exact.multiplier } else { result <- .Call(C_ttr_rollPercentRank, x, n, isTRUE(cumulative), exact.multiplier) } reclass(result, x) } ================================================ FILE: R/pivots.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # "pivots" <- function(data, lagts=TRUE) { # Author: Brian G. Peterson # http://www.investopedia.com/articles/forex/05/FXpivots.asp # http://www.investopedia.com/articles/technical/04/041404.asp # CentralPivot Point (P) = (High + Low + Close) / 3 center <- xts(rowSums(HLC(data))/3,order.by=index(data)) R1 <- (2*center)-Lo(data) # First Resistance (R1) = (2*P) - Low S1 <- (2*center)-Hi(data) # First Support (S1) = (2*P) - High R2 <- center + (R1 - S1) # Second Resistance (R2) = P + (R1-S1) S2 <- center - (R1 - S1) # Second Support (S2) = P - (R1- S1) ret <- cbind(center,R1,R2,S1,S2) colnames(ret) <- c('center','R1','R2','S1','S2') if(lagts){ newrow <- xts(t(rep(NA,5)), order.by=last(index(data))+1) ret <- rbind(ret,newrow) ret <- lag.xts(ret) } return(ret) } ================================================ FILE: R/priceBands.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Construct (optionally further smoothed and centered ) volatility bands around #' prices #' #' John Bollinger's famous adaptive volatility bands most often use the typical #' price of an HLC series, or may be calculated on a univariate price series #' (see \code{\link{BBands}}). #' #' This function applies a second moving average denoted by \code{fastn} to #' filter out higher-frequency noise, making the bands somewhat more stable to #' temporary fluctuations and spikes. #' #' If \code{centered} is \code{TRUE}, the function also further smoothes and #' centers the bands around a centerline adjusted to remove this higher #' frequency noise. If \code{lavg} is also \code{TRUE}, the smoothing applied #' for the middle band (but not the volatility bands) is doubled to further #' smooth the price-response function. #' #' If you have multiple different price series in \code{prices}, and want to use #' this function, call this functions using \code{lapply(prices,PBands,...)}. #' #' @aliases PBands priceBands #' @param prices A univariate series of prices. #' @param n Number of periods to average over. #' @param maType A function or a string naming the function to be called. #' @param sd The number of standard deviations to use. #' @param \dots any other pass-thru parameters, usually for function named by #' \code{maType}. #' @param fastn Number of periods to use for smoothing higher-frequency 'noise'. #' @param centered Whether to center the bands around a series adjusted for high #' frequency noise, default \code{FALSE}. #' @param lavg Whether to use a longer \code{(n*2)} smoothing period for #' centering, default \code{FALSE}. #' @return A object of the same class as \code{prices} or a matrix (if #' \code{try.xts} fails) containing the columns: #' \describe{ #' \item{ dn }{ The lower price volatility Band. } #' \item{ center }{ The smoothed centerline (see details). } #' \item{ up }{ The upper price volatility Band. } #' } #' @author Brian G. Peterson #' @seealso \code{\link{BBands}} #' @keywords ts #' @examples #' #' data(ttrc) #' pbands.close <- PBands( ttrc[,"Close"] ) #' #' @rdname priceBands PBands <- function(prices, n=20, maType="SMA", sd=2, ..., fastn=2, centered=FALSE, lavg=FALSE ) { # Price Bands, implemented by Brian G. Peterson # inspired by the univariate Bollinger Bands, and Ram Ben-David if(!is.vector(prices) && ncol(prices)>1) stop('prices should be a univariate series, maybe use', 'lapply(prices,PBands) instead?') prices <- try.xts(prices, error=as.matrix) # Default MA if(missing(maType)) { maType <- 'SMA' } maArgs <- list(n=n, ...) mavg <- do.call( maType, c( list(prices), maArgs ) ) maFastArgs <-list(n=fastn,...) fastmavg <- do.call( maType, c( list(prices), maFastArgs ) ) sdev <- runSD((mavg-fastmavg),n=n,sample=FALSE) if(!isTRUE(centered)){ center <- mavg } else { centerrun <- (mavg-fastmavg)/sdev if(isTRUE(lavg)){ maArgs <- list(n=(n*2), ...) } center <- mavg + ( do.call(maType, c( list(centerrun), maArgs ) ) ) } up <- center + sd * sdev dn <- center - sd * sdev res <- cbind(dn, center, up) colnames(res) <- c("dn", "center", "up") reclass(res, prices) } ================================================ FILE: R/rollFun.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Analysis of Running/Rolling/Moving Windows #' #' Various functions to analyze data over a moving window of periods. #' #' #' @aliases rollFun rollSFM #' @param Ra Object coercible to xts or matrix, containing the excess #' return for an individual security #' @param Rb Object coercible to xts or matrix, containing the market #' / benchmark return #' @param n Number of periods to use in the window #' #' @return A object of the same class as \code{Ra} (and \code{Rb}?) or a vector #' (if \code{try.xts} fails). #' \describe{ #' \item{rollSFM}{returns single-factor model parameters and R-squared #' over a n-period moving window.} #' } #' #' @author Joshua Ulrich #' @references The following site(s) were used to code/document this #' indicator: #' \url{https://en.wikipedia.org/wiki/Simple_linear_regression}\cr #' @keywords ts #' @rdname rollFun rollSFM <- function(Ra, Rb, n = 60) { # Calculate a rolling single-factor model # stopifnot(is.xts(Ra) && is.xts(Rb)) # calculate beta beta <- runCov(Ra, Rb, n) / runVar(Rb, n=n) # calculate alpha alpha <- runMean(Ra, n) - beta * runMean(Rb, n) # calculate R-squared se.resid <- 1/(n*(n-2)) * (n*runSum(Ra^2,n)-runSum(Ra,n)^2 - beta^2 * (n*runSum(Rb^2,n)-runSum(Rb,n)^2)) se.Ra <- runVar(Ra, n=n) * (n-1)/(n-2) r.squared <- 1 - se.resid / se.Ra result <- merge(alpha, beta, r.squared) return(result) } ================================================ FILE: R/runFun.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Analysis of Running/Rolling/Moving Windows #' #' Various functions to analyze data over a moving window of periods. #' #' #' @aliases runFun runSum runMin runMax runMean runMedian runCov runCor runVar #' runSD runMAD wilderSum #' @param x Object coercible to xts or matrix. #' @param y Object coercible to xts or matrix. #' @param n Number of periods to use in the window or, if #' \code{cumulative=TRUE}, the number of observations to use before the first #' result is returned. Must be between 1 and \code{nrow(x)}, inclusive. #' @param cumulative Logical, use from-inception calculation? #' @param sample Logical, sample covariance if \code{TRUE} (denominator of #' \code{n-1}) #' @param use Only \code{"all.obs"} currently implemented. #' @param non.unique One of 'mean', 'max', or 'min'; which compute their #' respective statistics for the two middle values of even-sized samples. #' @param center The values to use as the measure of central tendency, around #' which to calculate deviations. The default (\code{NULL}) uses the median. #' @param stat Statistic to calculate, one of 'median' or 'mean' (e.g. median #' absolute deviation or mean absolute deviation, respectively.) #' @param constant Scale factor applied to approximate the standard deviation. #' @return A object of the same class as \code{x} and \code{y} or a vector (if #' \code{try.xts} fails). #' \describe{ #' \item{runSum}{returns sums over a n-period moving window.} #' \item{runMin}{returns minimums over a n-period moving window.} #' \item{runMax}{returns maximums over a n-period moving window.} #' \item{runMean}{returns means over a n-period moving window.} #' \item{runMedian}{returns medians over a n-period moving window.} #' \item{runCov}{returns covariances over a n-period moving window.} #' \item{runCor}{returns correlations over a n-period moving window.} #' \item{runVar}{returns variances over a n-period moving window.} #' \item{runSD}{returns standard deviations over a n-period moving window.} #' \item{runMAD}{returns median/mean absolute deviations over a n-period moving window.} #' \item{wilderSum}{retuns a Welles Wilder style weighted sum over a n-period moving window.} #' } #' #' @author Joshua Ulrich #' @keywords ts #' @rdname runFun "runSum" <- function(x, n=10, cumulative=FALSE) { x <- try.xts(x, error=as.matrix) if( n < 1 || n > NROW(x) ) stop(sprintf("n = %d is outside valid range: [1, %d]", n, NROW(x))) if(NCOL(x) > 1) { stop("ncol(x) > 1. runSum only supports univariate 'x'") } if(cumulative) { # Count NAs, ensure they're only at beginning of data. NAs <- sum(is.na(x)) if( NAs > 0 ) { if( any( is.na(x[-(1:NAs)]) ) ) stop("Series contains non-leading NAs") if( NAs + n > NROW(x) ) stop("not enough non-NA values") } beg <- 1 + NAs # Initialize result vector result <- double(NROW(x)) result[beg:NROW(x)] <- cumsum(x[beg:NROW(x)]) # Replace 1:(n-1) with NAs is.na(result) <- seq_len(n-1+NAs) } else { # Call C routine result <- .Call(C_runsum, x, n) } # Convert back to original class reclass(result, x) } #-------------------------------------------------------------------------# #' @rdname runFun "runMin" <- function(x, n=10, cumulative=FALSE) { x <- try.xts(x, error=as.matrix) if(NCOL(x) > 1) { stop("ncol(x) > 1. runMin only supports univariate 'x'") } result <- runRange(x, n=n, cumulative=cumulative)[, 1] reclass(result, x) } #-------------------------------------------------------------------------# #' @rdname runFun "runMax" <- function(x, n=10, cumulative=FALSE) { x <- try.xts(x, error=as.matrix) if(NCOL(x) > 1) { stop("ncol(x) > 1. runMax only supports univariate 'x'") } result <- runRange(x, n=n, cumulative=cumulative)[, 2] reclass(result, x) } #' @rdname runFun "runRange" <- function(x, n=10, cumulative=FALSE) { x <- try.xts(x, error=as.matrix) if( n < 1 || n > NROW(x) ) stop(sprintf("n = %d is outside valid range: [1, %d]", n, NROW(x))) if(NCOL(x) > 1) { stop("ncol(x) > 1. runRange only supports univariate 'x'") } if(cumulative) { # Count NAs, ensure they're only at beginning of data, then remove. NAs <- sum( is.na(x) ) if( NAs > 0 ) { if( any( is.na(x[-(1:NAs)]) ) ) stop("Series contains non-leading NAs") if( NAs + n > NROW(x) ) stop("not enough non-NA values") } beg <- 1 + NAs # Initialize result matrix result <- matrix(NA_real_, nrow = NROW(x), ncol = 2) sub <- beg:NROW(x) result[sub,] <- cbind(cummin(x[sub]), cummax(x[sub])) # Replace 1:(n-1) with NAs and prepend NAs from original data is.na(result[seq_len(n-1+NAs), ]) <- TRUE } else { # Call C routine result <- .Call(C_runrange, x, n) } # Convert back to original class r <- reclass(result, x) colnames(r) <- c("min", "max") return(r) } #-------------------------------------------------------------------------# #' @rdname runFun "runMean" <- function(x, n=10, cumulative=FALSE) { if(cumulative) { x.na <- sum(is.na(x)) denom <- c(rep(NA_real_, x.na), seq_len(NROW(x)-x.na)) result <- runSum(x, n, cumulative) / denom } else { result <- runSum(x, n) / n } return(result) } #-------------------------------------------------------------------------# #' @rdname runFun "runMedian" <- function(x, n=10, non.unique="mean", cumulative=FALSE) { x <- try.xts(x, error=as.matrix) if( n < 1 || n > NROW(x) ) stop(sprintf("n = %d is outside valid range: [1, %d]", n, NROW(x))) if(NCOL(x) > 1) { stop("ncol(x) > 1. runMedian only supports univariate 'x'") } # Non-unique median non.unique <- match.arg(non.unique, c('mean','max','min')) non.unique <- switch(non.unique, mean=0L, max=1L, min=-1L) # Call C routine result <- .Call(C_runmedian, x, n, non.unique, cumulative) # Convert back to original class reclass(result, x) } #-------------------------------------------------------------------------# #' @rdname runFun "runCov" <- function(x, y, n=10, use="all.obs", sample=TRUE, cumulative=FALSE) { x <- try.xts(x, error=as.matrix) y <- try.xts(y, error=as.matrix) if(is.xts(x) && is.xts(y)) { xy <- cbind(x,y) } else { xy <- cbind( as.vector(x), as.vector(y) ) } if( n < 1 || n > NROW(x) ) stop(sprintf("n = %d is outside valid range: [1, %d]", n, NROW(x))) if(NCOL(x) > 1 || NCOL(y) > 1) { stop("ncol(x) > 1 or ncol(y) > 1.", " runCov only supports univariate 'x' and 'y'") } # "all.obs", "complete.obs", "pairwise.complete.obs" # Call C routine result <- .Call(C_runcov, xy[,1], xy[,2], n, sample, cumulative) # Convert back to original class # Should the attributes of *both* x and y be retained? reclass(result, x) } #-------------------------------------------------------------------------# #' @rdname runFun "runCor" <- function(x, y, n=10, use="all.obs", sample=TRUE, cumulative=FALSE) { result <- runCov(x, y, n, use=use, sample=sample, cumulative) / ( runSD(x, n, sample=sample, cumulative) * runSD(y, n, sample=sample, cumulative) ) return( result ) } #-------------------------------------------------------------------------# #' @rdname runFun "runVar" <- function(x, y=NULL, n=10, sample=TRUE, cumulative=FALSE) { if(is.null(y)) y <- x result <- runCov(x, y, n, use="all.obs", sample=sample, cumulative) return( result ) } #-------------------------------------------------------------------------# #' @rdname runFun "runSD" <- function(x, n=10, sample=TRUE, cumulative=FALSE) { result <- sqrt( runCov(x, x, n, use="all.obs", sample=sample, cumulative) ) return( result ) } #-------------------------------------------------------------------------# #' @rdname runFun "runMAD" <- function(x, n=10, center=NULL, stat="median", constant=1.4826, non.unique="mean", cumulative=FALSE) { x <- try.xts(x, error=as.matrix) if( n < 1 || n > NROW(x) ) stop(sprintf("n = %d is outside valid range: [1, %d]", n, NROW(x))) if(NCOL(x) > 1) { stop("ncol(x) > 1. runMAD only supports univariate 'x'") } if(is.null(center)) { center <- runMedian(x, n, cumulative=cumulative) } # Mean or Median absolute deviation? median <- match.arg(stat, c("mean","median")) median <- switch( stat, median=TRUE, mean=FALSE ) # Non-unique median non.unique <- match.arg(non.unique, c('mean','max','min')) non.unique <- switch( non.unique, mean=0, max=1, min=-1 ) # Call C routine result <- .Call(C_runmad, x, center, n, median, non.unique, cumulative) if( median ) result <- result * constant # Convert back to original class reclass(result, x) } #-------------------------------------------------------------------------# #' @rdname runFun "wilderSum" <- function(x, n=10) { x <- try.xts(x, error=as.matrix) if( n < 1 || n > NROW(x) ) stop(sprintf("n = %d is outside valid range: [1, %d]", n, NROW(x))) if(NCOL(x) > 1) { stop("ncol(x) > 1. wilderSum only supports univariate 'x'") } # Check for non-leading NAs # Leading NAs are handled in the C code naCheck(x, n) # called for error handling side-effect # Call C routine result <- .Call(C_wilderSum, x, n) # Convert back to original class reclass(result, x) } ================================================ FILE: R/stochastics.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Stochastic Oscillator / Stochastic Momentum Index #' #' The stochastic oscillator is a momentum indicator that relates the location #' of each day's close relative to the high/low range over the past \code{n} #' periods. Developed by George C. Lane in the late 1950s. The SMI relates #' the close to the midpoint of the high/low range. Developed by William Blau #' in 1993. #' #' If a High-Low-Close series is provided, the indicator is calculated using the #' high/low values. If a vector is provided, the calculation only uses that #' series. This allows stochastics to be calculated for: (1) series that have #' no HLC definition (e.g. foreign exchange), and (2) stochastic indicators #' (e.g. stochastic RSI - see examples). #' #' The \code{smooth} argument is the number of periods of internal smoothing to #' apply to the differences in the high-low-close range before calculating Fast #' K. Thanks to Stanley Neo for the suggestion. #' #' @aliases stochastics stochastic stoch SMI %K %D #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. If only a univariate series is given, it will be #' used. See details. #' @param n Number of periods to use. #' @param nFastK Number of periods for fast \%K (i.e. the number of past periods #' to use). #' @param nFastD Number of periods for fast \%D (i.e. the number smoothing #' periods to apply to fast \%K). #' @param nSlowD Number of periods for slow \%D (i.e. the number smoothing #' periods to apply to fast \%D). #' @param smooth Number of internal smoothing periods to be applied before #' calculating FastK. See Details. #' @param nFast Number of periods for initial smoothing. #' @param nSlow Number of periods for double smoothing. #' @param nSig Number of periods for signal line. #' @param maType Either: #' \enumerate{ #' \item A function or a string naming the function to be called. #' \item A \emph{list} with the first component like (1) above, and #' additional parameters specified as \emph{named} components. #' See Examples. #' } #' @param bounded Logical, should current period's values be used in the #' calculation? #' @param \dots Other arguments to be passed to the \code{maType} function in #' case (1) above. #' @return A object of the same class as \code{HLC} or a matrix (if #' \code{try.xts} fails) containing the columns: #' \describe{ #' \item{ fastK }{ Stochastic Fast \%K } #' \item{ fastD }{ Stochastic Fast \%D } #' \item{ slowD }{ Stochastic Slow \%D } #' \item{ SMI }{ Stochastic Momentum Index } #' \item{ signal }{ Stochastic Momentum Index signal line } #' } #' @note The calculation for William's \%R is similar to that of stochastics' #' fast \%K. #' #' The value for fast \%K will be 0.5 whenever the highest high and #' lowest low are the same over the last \code{n} periods. #' #' The stochastic oscillator and SMI calculate relative value of the close #' versus the high/low range and the midpoint of the high/low range, #' respectively. #' #' The stochastic oscillator and the stochastic momentum index are interpreted #' similarly. Readings below 20 (above 80) are considered oversold #' (overbought). However, readings below 20 (above 80) are not necessarily #' bearish (bullish). Lane believed some of the best sell (buy) signals #' occurred when the oscillator moved from overbought (oversold) back below 80 #' (above 20). #' #' For the stochastic oscillator, buy (sell) signals can also be given when \%K #' crosses above (below) \%D. Crossover signals are quite frequent however, #' which may result in whipsaws. #' @author Joshua Ulrich #' @seealso See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average #' options; and note Warning section. See \code{\link{WPR}} to compare it's #' results to fast \%K. #' @references The following site(s) were used to code/document these #' indicators: #' \cr Stochastic Oscillator:\cr #' \url{https://www.fmlabs.com/reference/StochasticOscillator.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=106}\cr #' \url{https://www.linnsoft.com/techind/stochastics}\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:stochastic_oscillator_fast_slow_and_full}\cr #' \cr SMI:\cr #' \url{https://www.fmlabs.com/reference/default.htm?url=SMI.htm}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' stochOSC <- stoch(ttrc[,c("High","Low","Close")]) #' stochWPR <- WPR(ttrc[,c("High","Low","Close")]) #' #' plot(tail(stochOSC[,"fastK"], 100), type="l", #' main="Fast %K and Williams %R", ylab="", #' ylim=range(cbind(stochOSC, stochWPR), na.rm=TRUE) ) #' lines(tail(stochWPR, 100), col="blue") #' lines(tail(1-stochWPR, 100), col="red", lty="dashed") #' #' stoch2MA <- stoch( ttrc[,c("High","Low","Close")], #' maType=list(list(SMA), list(EMA, wilder=TRUE), list(SMA)) ) #' #' SMI3MA <- SMI(ttrc[,c("High","Low","Close")], #' maType=list(list(SMA), list(EMA, wilder=TRUE), list(SMA)) ) #' #' stochRSI <- stoch( RSI(ttrc[,"Close"]) ) #' @rdname stochastics "stoch" <- function(HLC, nFastK=14, nFastD=3, nSlowD=3, maType, bounded=TRUE, smooth=1, ...) { # Stochastics HLC <- try.xts(HLC, error=as.matrix) # Calculation if HLC series is given if(NCOL(HLC)==3) { high <- HLC[,1] low <- HLC[,2] close <- HLC[,3] } else # Calculation if price vector is given if(NCOL(HLC)==1) { high <- HLC low <- HLC close <- HLC } else stop("Price series must be either High-Low-Close, or Close") if(bounded) { hmax <- runMax(high, nFastK) lmin <- runMin( low, nFastK) } else { hmax <- runMax(c(high[1],high[-NROW(HLC)]), nFastK) lmin <- runMin(c( low[1], low[-NROW(HLC)]), nFastK) } num <- close - lmin den <- hmax - lmin if(missing(maType)) { maType <- 'SMA' } # Case of two different 'maType's for both MAs. # e.g. stoch(price, 14, 3, 3, # maType=list(maUp=list(EMA,ratio=1/5), maDown=list(WMA,wts=1:10)) ) if( is.list(maType) ) { # Make sure maType is a list of lists maTypeInfo <- sapply(maType,is.list) if( !(all(maTypeInfo) && length(maTypeInfo) == 3) ) { stop("If \'maType\' is a list, you must specify\n ", "*three* MAs (see Examples section of ?stochastics)") } # If MA function has 'n' arg, see if it's populated in maType; # if it isn't, populate it with function's formal 'n' if( !is.null( formals(maType[[1]][[1]])$n ) && is.null( maType[[1]]$n ) ) { maType[[1]]$n <- nFastD } if( !is.null( formals(maType[[2]][[1]])$n ) && is.null( maType[[2]]$n ) ) { maType[[2]]$n <- nSlowD } if( !is.null( formals(maType[[3]][[1]])$n ) && is.null( maType[[3]]$n ) ) { maType[[3]]$n <- smooth } numMA <- do.call( maType[[3]][[1]], c( list(num), maType[[3]][-1] ) ) denMA <- do.call( maType[[3]][[1]], c( list(den), maType[[3]][-1] ) ) fastK <- numMA / denMA fastK[!is.finite(fastK) & !is.na(fastK)] <- 0.5 fastD <- do.call( maType[[1]][[1]], c( list(fastK), maType[[1]][-1] ) ) slowD <- do.call( maType[[2]][[1]], c( list(fastD), maType[[2]][-1] ) ) } # Case of one 'maType' for both MAs. # e.g. stoch(price, 14, 3, 3, maType="WMA", wts=volume ) else { numMA <- do.call( maType, c( list(num), list(n=smooth) ) ) denMA <- do.call( maType, c( list(den), list(n=smooth) ) ) fastK <- numMA / denMA fastK[!is.finite(fastK) & !is.na(fastK)] <- 0.5 fastD <- do.call( maType, c( list(fastK), list(n=nFastD, ...) ) ) slowD <- do.call( maType, c( list(fastD), list(n=nSlowD, ...) ) ) } result <- cbind( fastK, fastD, slowD ) colnames(result) <- c( "fastK", "fastD", "slowD" ) reclass(result, HLC) } #-------------------------------------------------------------------------# #' @rdname stochastics "SMI" <- function(HLC, n=13, nFast=2, nSlow=25, nSig=9, maType, bounded=TRUE, ...) { # Stochastic Momentum Index # Not Validated # http://www.fmlabs.com/reference/default.htm?url=SMI.htm # The median in the SMI formula on the above site is incorrect. # Calculation if HLC series is given if(ncol(HLC)==3) { high <- HLC[,1] low <- HLC[,2] close <- HLC[,3] } else # Calculation if price vector is given if(ncol(HLC)==1) { high <- HLC low <- HLC close <- HLC } else stop("Price series must be either High-Low-Close, or Close") if(bounded) { hmax <- runMax(high, n) lmin <- runMin( low, n) } else { hmax <- runMax(c(high[1],high[-NROW(HLC)]), n) lmin <- runMax(c( low[1], low[-NROW(HLC)]), n) } hmax <- ifelse( is.na(hmax), high, hmax ) lmin <- ifelse( is.na(lmin), low, lmin ) HLdiff <- hmax - lmin Cdiff <- close - ( hmax + lmin ) / 2 if(missing(maType)) { maType <- 'EMA' } # Case of two different 'maType's for both MAs. # e.g. SMI(price, 13, 2, 25, 9, # maType=list(maUp=list(EMA,ratio=1/5), maDown=list(WMA,wts=1:10)) ) if( is.list(maType) ) { # Make sure maType is a list of lists maTypeInfo <- sapply(maType,is.list) if( !(all(maTypeInfo) && length(maTypeInfo) == 3) ) { stop("If \'maType\' is a list, you must specify\n ", "*three* MAs (see Examples section of ?SMI)") } # If MA function has 'n' arg, see if it's populated in maType; # if it isn't, populate it with function's formal 'n' if( !is.null( formals(maType[[1]][[1]])$n ) && is.null( maType[[1]]$n ) ) { maType[[1]]$n <- nFast } if( !is.null( formals(maType[[2]][[1]])$n ) && is.null( maType[[2]]$n ) ) { maType[[2]]$n <- nSlow } if( !is.null( formals(maType[[3]][[1]])$n ) && is.null( maType[[3]]$n ) ) { maType[[3]]$n <- nSig } num1 <- do.call( maType[[1]][[1]], c( list(Cdiff ), maType[[1]][-1] ) ) den1 <- do.call( maType[[1]][[1]], c( list(HLdiff), maType[[1]][-1] ) ) num2 <- do.call( maType[[2]][[1]], c( list( num1 ), maType[[2]][-1] ) ) den2 <- do.call( maType[[2]][[1]], c( list( den1 ), maType[[2]][-1] ) ) SMI <- 100 * ( num2 / ( den2 / 2 ) ) signal <- do.call( maType[[3]][[1]], c( list(SMI), maType[[3]][-1] ) ) } # Case of one 'maType' for both MAs. # e.g. SMI(price, 13, 2, 25, 9, maType="WMA", wts=volume ) else { num1 <- do.call( maType, c( list(Cdiff ), list(n=nSlow, ... ) ) ) den1 <- do.call( maType, c( list(HLdiff), list(n=nSlow, ... ) ) ) num2 <- do.call( maType, c( list( num1 ), list(n=nFast, ... ) ) ) den2 <- do.call( maType, c( list( den1 ), list(n=nFast, ... ) ) ) SMI <- 100 * ( num2 / ( den2 / 2 ) ) signal <- do.call( maType, c( list(SMI), list(n=nSig, ... ) ) ) } result <- cbind( SMI, signal ) colnames(result) <- c( "SMI", "signal" ) reclass( result, HLC ) } ================================================ FILE: R/ultimateOscillator.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' The Ultimate Oscillator #' #' The Ultimate Oscillator is a momentum oscillator designed to capture momentum across three #' different time frames. #' #' Created by Larry Williams in 1976. #' #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. #' @param n A vector of the number of periods to use for each average calculation. #' @param wts The weights applied to each average. #' @author Ivan Popivanov #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://school.stockcharts.com/doku.php?id=technical_indicators:ultimate_oscillator}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' ult.osc <- ultimateOscillator(ttrc[,c("High","Low","Close")]) #' ultimateOscillator <- function(HLC, n=c(7,14,28), wts=c(4,2,1)) { # Ultimate Oscillator if(length(n) != 3 || length(wts) != 3) stop("length(n) and length(wts) must both be 3") HLC <- try.xts(HLC, error=as.matrix) # avoid reclassing in ATR and runSum HLC.RECLASS <- attr(HLC, ".RECLASS") attr(HLC, ".RECLASS") <- FALSE # only need 'tr' and 'trueLow' atr <- ATR(HLC, n=1) buyPressure <- HLC[,3] - atr[,'trueLow'] osc <- buyPressure * 0.0 for(i in 1:3) { osc <- osc + wts[i] * (runSum(buyPressure, n[i]) / runSum(atr[,'tr'], n[i])) } osc <- 100.0 * osc / sum(wts) # restore HLC .RECLASS attribute attr(HLC, ".RECLASS") <- HLC.RECLASS reclass(osc, HLC) } ================================================ FILE: R/volatility.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Volatility #' #' Selected volatility estimators/indicators; various authors. #' #' \itemize{ #' \item Close-to-Close Volatility (\code{calc="close"})\cr #' \deqn{ \sigma_{cl} = \sqrt{\frac{N}{n-2} \sum_{i=1}^{n-1}(r_i-\bar{r})^2} #' }{sqrt(N) * runSD(ROC(Cl), n-1)} #' \deqn{where\;\; r_i = \log \left(\frac{C_i}{C_{i-1}}\right) } #' \deqn{and\;\; \bar{r} = \frac{r_1+r_2+\ldots +r_{n-1}}{n-1} } #' #' \item OHLC Volatility: Garman and Klass (\code{calc="garman.klass"})\cr The #' Garman and Klass estimator for estimating historical volatility assumes #' Brownian motion with zero drift and no opening jumps (i.e. the opening = #' close of the previous period). This estimator is 7.4 times more efficient #' than the close-to-close estimator.\cr #' \deqn{ \sigma = \sqrt{ \frac{N}{n} \sum #' \left[ \textstyle\frac{1}{2}\displaystyle #' \left( \log \frac{H_i}{L_i} \right)^2 - (2\log 2-1) #' \left( \log \frac{C_i}{O_i} \right)^2 \right] } #' }{sqrt(N/n * runSum(0.5 * log(Hi/Lo)^2 - #' (2*log(2)-1) * log(Cl/Op)^2, n))} #' #' \item High-Low Volatility: Parkinson (\code{calc="parkinson"})\cr #' The Parkinson formula for estimating the historical volatility of #' an underlying based on high and low prices.\cr #' \deqn{ \sigma = \sqrt{ \frac{N}{4 n \times \log 2} \sum_{i=1}^{n} #' \left(\log \frac{H_i}{L_i}\right)^2} #' }{sqrt(N/(4*n*log(2)) * runSum(log(Hi/Lo)^2, n))} #' #' \item OHLC Volatility: Rogers and Satchell (\code{calc="rogers.satchell"})\cr #' The Roger and Satchell historical volatility estimator allows for non-zero #' drift, but assumed no opening jump.\cr #' \deqn{ \sigma = \sqrt{ \textstyle\frac{N}{n} \sum \left[ #' \log \textstyle\frac{H_i}{C_i} \times \log \textstyle\frac{H_i}{O_i} + #' \log \textstyle\frac{L_i}{C_i} \times \log \textstyle\frac{L_i}{O_i} \right] } #' }{sqrt(N/n * runSum(log(Hi/Cl) * log(Hi/Op) + #' log(Lo/Cl) * log(Lo/Op), n))} #' #' \item OHLC Volatility: Garman and Klass - Yang and Zhang #' (\code{calc="gk.yz"})\cr This estimator is a modified version of the Garman #' and Klass estimator that allows for opening gaps.\cr #' \deqn{ \sigma = \sqrt{ \textstyle\frac{N}{n} \sum \left[ #' \left( \log \textstyle\frac{O_i}{C_{i-1}} \right)^2 + #' \textstyle\frac{1}{2}\displaystyle #' \left( \log \textstyle\frac{H_i}{L_i} \right)^2 - (2 \times \log 2-1) #' \left( \log \textstyle\frac{C_i}{O_i} \right)^2 \right] } #' }{sqrt(N/n * runSum(log(Op/lag(Cl,1))^2 + #' 0.5 * log(Hi/Lo)^2 - (2*log(2)-1) * log(Cl/Op)^2 , n))} #' #' \item OHLC Volatility: Yang and Zhang (\code{calc="yang.zhang"})\cr The Yang #' and Zhang historical volatility estimator has minimum estimation error, and #' is independent of drift and opening gaps. It can be interpreted as a #' weighted average of the Rogers and Satchell estimator, the close-open #' volatility, and the open-close volatility. #' #' Users may override the default values of \eqn{\alpha} (1.34 by default) or #' \eqn{k} used in the calculation by specifying \code{alpha} or \code{k} in #' \code{\dots}, respectively. Specifying \code{k} will cause \code{alpha} to be #' ignored, if both are provided.\cr #' \deqn{ \sigma^2 = \sigma_o^2 + k\sigma_c^2 + (1-k)\sigma_{rs}^2 #' }{ s <- sqrt(s2o + k*s2c + (1-k)*(s2rs^2)) } #' \deqn{ \sigma_o^2 =\textstyle \frac{N}{n-1} \sum #' \left( \log \frac{O_i}{C_{i-1}}-\mu_o \right)^2 #' }{ s2o <- N * runVar(log(Op/lag(Cl,1)), n=n) } #' \deqn{ \mu_o=\textstyle \frac{1}{n} \sum \log \frac{O_i}{C_{i-1}} } #' \deqn{ \sigma_c^2 =\textstyle \frac{N}{n-1} \sum #' \left( \log \frac{C_i}{O_i}-\mu_c \right)^2 #' }{ s2c <- N * runVar(log(Cl/Op), n=n) } #' \deqn{ \mu_c=\textstyle \frac{1}{n} \sum \log \frac{C_i}{O_i} } #' \deqn{ \sigma_{rs}^2 = \textstyle\frac{N}{n} \sum \left( #' \log \textstyle\frac{H_i}{C_i} \times \log \textstyle\frac{H_i}{O_i} + #' \log \textstyle\frac{L_i}{C_i} \times \log \textstyle\frac{L_i}{O_i} #' \right) #' }{ s2rs <- volatility(OHLC, n, "rogers.satchell", N, ...) } #' \deqn{ k=\frac{\alpha-1}{alpha+\frac{n+1}{n-1}} #' }{ k <- (alpha-1) / (alpha + (n+1)/(n-1)) } #' } #' #' @aliases volatility garman.klass parkinson rogers.satchell gk.yz yang.zhang #' @param OHLC Object that is coercible to xts or matrix and contains #' Open-High-Low-Close prices (or only Close prices, if \code{calc="close"}). #' @param n Number of periods for the volatility estimate. #' @param calc The calculation (type) of estimator to use. #' @param N Number of periods per year. #' @param mean0 Use a mean of 0 rather than the sample mean. #' @param \dots Arguments to be passed to/from other methods. #' @return A object of the same class as \code{OHLC} or a vector (if #' \code{try.xts} fails) containing the chosen volatility estimator values. #' @author Joshua Ulrich #' @seealso See \code{\link{TR}} and \code{\link{chaikinVolatility}} for other #' volatility measures. #' @references The following sites were used to code/document these #' indicators. All were created by Thijs van den Berg under the GNU Free #' Documentation License and were retrieved on 2008-04-20. The original #' links are dead, but can be accessed via internet archives.\cr #' \cr Close-to-Close Volatility (\code{calc="close"}):\cr #' \url{https://web.archive.org/web/20100421083157/http://www.sitmo.com/eq/172}\cr #' \cr OHLC Volatility: Garman Klass (\code{calc="garman.klass"}):\cr #' \url{https://web.archive.org/web/20100326172550/http://www.sitmo.com/eq/402}\cr #' \cr High-Low Volatility: Parkinson (\code{calc="parkinson"}):\cr #' \url{https://web.archive.org/web/20100328195855/http://www.sitmo.com/eq/173}\cr #' \cr OHLC Volatility: Rogers Satchell (\code{calc="rogers.satchell"}):\cr #' \url{https://web.archive.org/web/20091002233833/http://www.sitmo.com/eq/414}\cr #' \cr OHLC Volatility: Garman Klass - Yang Zhang (\code{calc="gk.yz"}):\cr #' \url{https://web.archive.org/web/20100326215050/http://www.sitmo.com/eq/409}\cr #' \cr OHLC Volatility: Yang Zhang (\code{calc="yang.zhang"}):\cr #' \url{https://web.archive.org/web/20100326215050/http://www.sitmo.com/eq/409}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' ohlc <- ttrc[,c("Open","High","Low","Close")] #' vClose <- volatility(ohlc, calc="close") #' vClose0 <- volatility(ohlc, calc="close", mean0=TRUE) #' vGK <- volatility(ohlc, calc="garman") #' vParkinson <- volatility(ohlc, calc="parkinson") #' vRS <- volatility(ohlc, calc="rogers") #' "volatility" <- function(OHLC, n=10, calc="close", N=260, mean0=FALSE, ...) { OHLC <- try.xts(OHLC, error=as.matrix) # Choose an arg name that doesn't clash with ROC's 'type' arg calc <- match.arg(calc, c("close","garman.klass","parkinson", "rogers.satchell","gk.yz","yang.zhang")) # s Volatility # N Number of closing prices in a year # n Number of historical prices used for the volatility estimate # ci The closing price on the ith day # ri Log return on the ith day # Historical Close-to-Close Volatility # http://www.sitmo.com/eq/172 if( calc=="close" ) { # Add univariate case from Cedrick Johnson's R-SIG-Finance post if( NCOL(OHLC) == 1 ) { r <- ROC(OHLC[, 1], 1, ...) } else { r <- ROC(OHLC[, 4], 1, ...) } if( isTRUE(mean0) ) { # This is an alternative SD calculation using an effective mean of 0 s <- sqrt(N) * sqrt(runSum(r^2, n-1) / (n-2)) } else { # This is the standard SD calculation using the sample mean s <- sqrt(N) * runSD(r, n-1) } } # Historical Open-High-Low-Close Volatility: Garman Klass # http://www.sitmo.com/eq/402 if( calc=="garman.klass" ) { s <- sqrt( N/n * runSum( .5 * log(OHLC[,2]/OHLC[,3])^2 - (2*log(2)-1) * log(OHLC[,4]/OHLC[,1])^2 , n ) ) } if( calc=="parkinson" ) { # Historical High-Low Volatility: Parkinson # http://www.sitmo.com/eq/173 s <- sqrt( N/(4*n*log(2)) * runSum( log(OHLC[,2]/OHLC[,3])^2, n ) ) } if( calc=="rogers.satchell" ) { # Historical Open-High-Low-Close Volatility: Rogers Satchell # http://www.sitmo.com/eq/414 s <- sqrt( N/n * runSum( log(OHLC[,2]/OHLC[,4]) * log(OHLC[,2]/OHLC[,1]) + log(OHLC[,3]/OHLC[,4]) * log(OHLC[,3]/OHLC[,1]), n ) ) } if( calc=="gk.yz" ) { #if( calc=="garman.klass.yang.zhang" ) { # Historical Open-High-Low-Close Volatility: Garman and Klass (Yang Zhang) # http://www.sitmo.com/eq/409 if(is.xts(OHLC)) { Cl1 <- lag.xts(OHLC[,4]) } else { Cl1 <- c( NA, OHLC[-NROW(OHLC),4] ) } s <- sqrt( N/n * runSum( log(OHLC[,1]/Cl1)^2 + .5 * log(OHLC[,2]/OHLC[,3])^2 - (2*log(2)-1) * log(OHLC[,4]/OHLC[,1])^2 , n) ) #s <- sqrt( Z/n * runSum( # log(op/cl[-1])^2 + # .5*log(hi/lo)^2 - # (2*log(2)-1)*log(cl/op)^2 ) ) } if( calc=="yang.zhang" ) { # Historical Open-High-Low-Close Volatility: Yang Zhang # http://www.sitmo.com/eq/417 if(is.xts(OHLC)) { Cl1 <- lag.xts(OHLC[,4]) } else { Cl1 <- c( NA, OHLC[-NROW(OHLC),4] ) } dots <- list(...) if(is.null(dots$alpha)) { alpha <- 1.34 } if(is.null(dots$k)) { k <- (alpha-1) / ( alpha + (n+1)/(n-1) ) } s2o <- N * runVar(log(OHLC[,1] / Cl1), n=n) s2c <- N * runVar(log(OHLC[,4] / OHLC[,1]), n=n) s2rs <- volatility(OHLC=OHLC, n=n, calc="rogers.satchell", N=N, ...) s <- sqrt(s2o + k*s2c + (1-k)*(s2rs^2)) } reclass(s,OHLC) } ================================================ FILE: R/williamsAD.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2007-2013 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #' Williams Accumulation / Distribution #' #' The Williams Accumulation / Distribution (AD) line is a measure of market #' momentum. Developed by Larry Williams. #' #' The Williams AD line differs from OBV and chaikinAD in that it doesn't take #' volume into account. #' #' @param HLC Object that is coercible to xts or matrix and contains #' High-Low-Close prices. #' @return A object of the same class as \code{HLC} or a vector (if #' \code{try.xts} fails) containing the accumulation / distribution values. #' @note The Accumulation/Distribution Line is interpreted by looking for a #' divergence in the direction of the indicator relative to price. #' @author Joshua Ulrich #' @seealso See \code{\link{OBV}}, \code{\link{chaikinAD}}, and #' \code{\link{ATR}}. #' @references The following site(s) were used to code/document this #' indicator:\cr #' \url{https://www.fmlabs.com/reference/WilliamsAD.htm}\cr #' \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=125}\cr #' @keywords ts #' @examples #' #' data(ttrc) #' ad <- williamsAD(ttrc[,c("High","Low","Close")]) #' "williamsAD" <- function(HLC) { # Williams Accumulation/Distribution HLC <- try.xts(HLC, error=as.matrix) # Calculate change in close, and true high/low dCl <- momentum(HLC[,3], 1) atr <- ATR(HLC) # Calculate AD ad <- HLC[,3] - ifelse( dCl > 0, atr[,"trueLow"], atr[,"trueHigh"] ) ad[ dCl == 0 ] <- 0 ad.na <- naCheck(ad) ad <- cumsum( ad[ad.na$nonNA] ) ad <- c( rep( NA, ad.na$NAs ), ad ) reclass(ad, HLC) } ================================================ FILE: R/zzz.R ================================================ # # TTR: Technical Trading Rules # # Copyright (C) 2017 Joshua M. Ulrich # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # .env <- new.env() .onUnload <- function(libpath) { library.dynam.unload("TTR", libpath) } ================================================ FILE: README.md ================================================ ### About TTR is an [R](https://www.r-project.org) package that provides the most popular technical analysis functions for financial market data. Many of these functions are used as components of systematic trading strategies and financial charts. ### Supporting TTR development If you are interested in supporting the ongoing development and maintenance of TTR, please consider [becoming a sponsor](https://github.com/sponsors/joshuaulrich). ### Installation The current release is available on [CRAN](https://CRAN.R-project.org/package=TTR), which you can install via: ```r install.packages("TTR") ``` To install the development version, you need to clone the repository and build from source, or run one of: ```r # lightweight remotes::install_github("joshuaulrich/TTR") # or devtools::install_github("joshuaulrich/TTR") ``` You will need tools to compile C/C++ code. See the relevant appendix in the [R Installation and Administration manual](https://cran.r-project.org/doc/manuals/r-release/R-admin.html) for your operating system: - [Windows](https://cran.r-project.org/doc/manuals/r-release/R-admin.html#The-Windows-toolset) - [MacOS](https://cran.r-project.org/doc/manuals/r-release/R-admin.html#macOS) (the [R for Mac OS X Developer's Page](https://mac.R-project.org/) might also be helpful) - [Unix-alike](https://cran.r-project.org/doc/manuals/r-release/R-admin.html#Essential-and-useful-other-programs-under-a-Unix_002dalike) ### Getting Started Here are a few examples of some of the more well-known indicators: ```r # "TTR Composite" (simulated data) data(ttrc) hlc <- ttrc[, c("High", "Low", "Close")] # Bollinger Bands bbands <- BBands(hlc) # Directional Movement Index adx <- ADX(hlc) # Moving Averages ema <- EMA(ttrc[, "Close"], n = 20) sma <- SMA(ttrc[, "Close"], n = 20) # MACD macd <- MACD(ttrc[,"Close"]) # RSI rsi <- RSI(ttrc[,"Close"]) # Stochastics stochOsc <- stoch(hlc) ``` TTR works with the `chartSeries()` function in [quantmod](https://github.com/joshuaulrich/quantmod). Here's an example that uses `chartSeries()` and adds TTR-calculated indicators and overlays to the chart. ```r library(quantmod) data(ttrc) # create an xts object x <- as.xts(ttrc) chartSeries(x, subset = "2006-09/", theme = "white") addBBands() addRSI() ``` ![](https://drive.google.com/uc?export=view&id=1TrgoZujgcI9GCMEWHlDgzkQQvBItyLwq) ### Have a question? Ask your question on [Stack Overflow](https://stackoverflow.com/questions/tagged/r) or the [R-SIG-Finance](https://stat.ethz.ch/mailman/listinfo/r-sig-finance) mailing list (you must subscribe to post). ### Contributing Please see the [Contributing Guide](https://github.com/joshuaulrich/TTR/wiki/Contributing-Guide). ### See Also - [quantmod](https://CRAN.R-project.org/package=quantmod): quantitative financial modeling framework - [xts](https://CRAN.R-project.org/package=xts): eXtensible Time Series based on [zoo](https://CRAN.R-project.org/package=zoo) ### Author [Joshua Ulrich](https://about.me/joshuaulrich) ================================================ FILE: THANKS ================================================ In no particular order: - I can't thank Jeff Ryan enough for all his help with TTR via: motivation to submit TTR to CRAN, helpful comments, testing, and providing an example Fortran implementation of 'EMA' (from which all other included Fortran functions are based). - Many thanks to Ion Georgiadis for helpful suggestions and testing. ================================================ FILE: inst/tinytest/test-dvi.R ================================================ # Create input data data(ttrc) rownames(ttrc) <- ttrc$Date ttrc$Date <- NULL # Run test dat <- setNames(ttrc$Close, rownames(ttrc)) dvi <- DVI(dat) expect_equal(colnames(dvi), c("dvi.mag", "dvi.str", "dvi")) ================================================ FILE: inst/tinytest/test-misc.R ================================================ # Create input data data(ttrc) rownames(ttrc) <- ttrc$Date ttrc$Date <- NULL input <- list( all=ttrc[1:250,], top=ttrc[1:250,], mid=ttrc[1:250,] ) input$top[1:10,] <- NA input$mid[9:20,] <- NA #iAll <- as.matrix(ttrc[1:250,]) iAll <- ttrc[1:250,] iTop <- iAll; iTop[1:10,] <- NA iMid <- iAll; iMid[9:20,] <- NA hl <- c('High','Low') hlc <- c('High','Low','Close') cl <- 'Close' # Load output data load(system.file("tinytest/output/misc.rda", package="TTR")) ################################################# # Rate-of-Change roc <- ROC(iAll[,cl], type='continuous') expect_equal( roc, output$allROCc ) expect_equal( attributes(roc), attributes(output$allROCc) ) #expect_equal( ROC(input$top$Close, type='continuous'), output$topROCc ) #expect_error( ROC(input$mid$Close) ) roc <- ROC(input$all$Close, type='discrete') expect_equal( roc, output$allROCd ) expect_equal( attributes(roc), attributes(output$allROCd) ) #expect_equal( ROC(input$top$Close, type='discrete'), output$topROCd ) # Momentum mom <- momentum(input$all$Close) expect_equal( mom, output$allMom ) expect_equal( attributes(mom), attributes(output$allMom) ) #expect_equal( momentum(input$top$Close), output$topMom ) #expect_error( momentum(input$mid$Close) ) # Close Location Value ia <- iAll[,hlc]; rownames(ia) <- NULL it <- iTop[,hlc]; rownames(it) <- NULL oa <- as.data.frame(output$allCLV); rownames(oa) <- rownames(ia) ot <- as.data.frame(output$topCLV); rownames(ot) <- rownames(it) expect_equal( CLV(ia), output$allCLV ) expect_equal( attributes(CLV(ia)), attributes(output$allCLV) ) expect_equal( CLV(it), output$topCLV ) expect_equal( attributes(CLV(it)), attributes(output$topCLV) ) # Arms' Ease of Movement ia <- iAll[,hl]; rownames(ia) <- NULL emv.all <- EMV(ia, input$all$Volume) expect_equal( emv.all, output$allEMV ) expect_equal( attributes(emv.all), attributes(output$allEMV) ) #emv.top<- EMV(input$top[,c('High','Low')], input$top$Volume) #expect_equal( emv.top, output$topEMV ) #expect_equal( attributes(emv.top), attributes(output$topEMV) ) #expect_error( EMV(input$mid[,c('High','Low')], input$mid$Volume) ) #expect_error( EMV(input$all[,c('High','Low')], input$mid$Volume) ) #expect_error( EMV(input$mid[,c('High','Low')], input$all$Volume) ) # Know Sure Thing expect_equal( KST(input$all$Close), output$allKST ) expect_equal( attributes(KST(input$all$Close)), attributes(output$allKST) ) #expect_equal( KST(input$top$Close), output$topKST ) #expect_error( KST(input$mid$Close) ) # CTI expect_equal(length(input$all$Close), length(CTI(input$all$Close))) ================================================ FILE: inst/tinytest/test-moving-averages.R ================================================ # Create input data data(ttrc) rownames(ttrc) <- ttrc$Date ttrc$Date <- NULL input <- list( all=ttrc[1:250,], top=ttrc[1:250,], mid=ttrc[1:250,] ) input$top[1:10,] <- NA input$mid[9:20,] <- NA # Load output data load(system.file("tinytest/output/moving-averages.rda", package="TTR")) ################################################# # ALMA v <- 1:10 x <- xts::.xts(v, seq_along(v)) av <- ALMA(v) ax <- ALMA(x) expect_equal(NROW(av), NROW(ax)) # Simple Moving Average expect_equal( SMA(input$all$Close), output$allSMA ) expect_equal( attributes(SMA(input$all$Close)), attributes(output$allSMA) ) expect_equal( SMA(input$top$Close), output$topSMA ) expect_equal( attributes(SMA(input$top$Close)), attributes(output$topSMA) ) expect_error( SMA(input$mid$Close) ) expect_error( SMA(input$all[,1:2]) ) # Exponential Moving Average expect_equal( EMA(input$all$Close), output$allEMA ) expect_equal( attributes(EMA(input$all$Close)), attributes(output$allEMA) ) expect_equal( EMA(input$top$Close), output$topEMA ) expect_equal( attributes(EMA(input$top$Close)), attributes(output$topEMA) ) expect_error( EMA(input$mid$Close) ) expect_error( EMA(input$all[,1:2]) ) expect_error( EMA(input$all$Close, n = -1) ) expect_error( EMA(input$all$Close, n = NROW(input$all) + 1) ) out <- 0:9 * 1.0 is.na(out) <- 1:2 expect_equal(EMA(1:10, ratio = 0.5), out) expect_equal(EMA(1:10, n = 3), out) expect_warning(ema_n_ratio <- EMA(1:10, n = 3, ratio = 0.5), info = "'n' and 'ratio' specified") expect_equal(ema_n_ratio, out) expect_error(EMA(1:10, ratio = 0.0), info = "ratio = 0") # Exponential Moving Average, Wilder ratio expect_equal( EMA(input$all$Close, wilder=TRUE), output$allEMAwilder ) expect_equal( attributes(EMA(input$all$Close, wilder=TRUE)), attributes(output$allEMAwilder) ) expect_equal( EMA(input$top$Close, wilder=TRUE), output$topEMAwilder ) expect_equal( attributes(EMA(input$top$Close, wilder=TRUE)), attributes(output$topEMAwilder) ) expect_error( EMA(input$mid$Close, wilder=TRUE) ) # Double-Exponential Moving Average expect_equal( DEMA(input$all$Close), output$allDEMA ) expect_equal( attributes(DEMA(input$all$Close)), attributes(output$allDEMA) ) expect_equal( DEMA(input$top$Close), output$topDEMA ) expect_equal( attributes(DEMA(input$top$Close)), attributes(output$topDEMA) ) expect_error( DEMA(input$mid$Close) ) expect_error( DEMA(input$all[,1:2]) ) # Hull Moving Average hma <- HMA(1:10, 2) expect_equal(hma, c(NA, 2:10 + 1/3)) hma <- HMA(1:10, 3) expect_equal(hma, c(rep(NA, 2), 3:10 + 2/3)) # Weighted Moving Average, 1:n expect_equal( WMA(input$all$Close), output$allWMA ) expect_equal( attributes(WMA(input$all$Close)), attributes(output$allWMA) ) expect_equal( WMA(input$top$Close), output$topWMA ) expect_equal( attributes(WMA(input$top$Close)), attributes(output$topWMA) ) expect_error( WMA(input$mid$Close) ) expect_error( WMA(input$all$Close, wts=1) ) expect_error( WMA(input$all[,1:2]) ) expect_error( WMA(input$all$Close, n = -1) ) expect_error( WMA(input$all$Close, n = NROW(input$all) + 1) ) # Weighted Moving Average, Volume expect_equal( WMA(input$all$Close, wts=input$all$Volume), output$allWMAvol ) expect_equal( attributes(WMA(input$all$Close, wts=input$all$Volume)), attributes(output$allWMAvol) ) expect_equal( WMA(input$top$Close, wts=input$top$Volume), output$topWMAvol ) expect_equal( attributes(WMA(input$top$Close, wts=input$top$Volume)), attributes(output$topWMAvol) ) expect_error( WMA(input$all$Close, wts=input$mid$Volume) ) expect_error( WMA(input$all[,1:2], wts=input$all$Volume) ) expect_error( WMA(input$all$Close, wts=input$all[,1:2]) ) x <- xts::.xts(x = c(NA, 1:3), 1:4) wma <- WMA(x, 2) expect_true(inherits(wma, "xts")) # Exponential, Volume-Weighted Moving Average expect_equal( EVWMA(input$all$Close, input$all$Volume), output$allEVWMA ) expect_equal( attributes(EVWMA(input$all$Close, input$all$Volume)), attributes(output$allEVWMA) ) expect_equal( EVWMA(input$top$Close, input$top$Volume), output$topEVWMA ) expect_equal( attributes(EVWMA(input$top$Close, input$top$Volume)), attributes(output$topEVWMA) ) expect_error( EVWMA(input$mid$Close, input$mid$Volume) ) expect_error( EVWMA(input$all$Close) ) expect_error( EVWMA(input$all[,1:2], input$all$Volume) ) expect_error( EVWMA(input$all$Close, input$all[,1:2]) ) expect_error( EVWMA(input$all$Close, n = -1) ) expect_error( EVWMA(input$all$Close, n = NROW(input$all) + 1) ) # Zero-Lag Exponential Moving Average expect_equal( ZLEMA(input$all$Close), output$allZLEMA ) expect_equal( attributes(ZLEMA(input$all$Close)), attributes(output$allZLEMA) ) expect_equal( ZLEMA(input$top$Close), output$topZLEMA ) expect_equal( attributes(ZLEMA(input$top$Close)), attributes(output$topZLEMA) ) expect_error( ZLEMA(input$mid$Close) ) expect_error( ZLEMA(input$all[,1:2]) ) out <- c(rep(NA, 6), 4.0, 6.0, 7.75, 9.3125) expect_equal(ZLEMA(1:10, ratio = 0.25), out) expect_equal(ZLEMA(1:10, n = 7), out) expect_warning(zlema_n_ratio <- ZLEMA(1:10, n = 7, ratio = 0.25), info = "'n' and 'ratio' specified") expect_equal(zlema_n_ratio, out) expect_error(ZLEMA(1:10, ratio = 0.0), info = "ratio = 0") x <- c(NA, rnorm(10)) expect_silent(EMA(x, 10), info = "non-na equals 'n' does not error") expect_silent(ZLEMA(x, 10), info = "non-na equals 'n' does not error") # column names x <- xts::as.xts(ttrc) p <- x[, "Close"] v <- x[, "Volume"] expect_equal("SMA", colnames(SMA(p))) expect_equal("EMA", colnames(EMA(p))) expect_equal("DEMA", colnames(DEMA(p))) expect_equal("WMA", colnames(WMA(p))) expect_equal("EVWMA", colnames(EVWMA(p, v))) expect_equal("ZLEMA", colnames(ZLEMA(p))) expect_equal("VWAP", colnames(VWAP(p, v))) expect_equal("HMA", colnames(HMA(p))) expect_equal("ALMA", colnames(ALMA(p))) ================================================ FILE: inst/tinytest/test-oscillators.R ================================================ # Create input data data(ttrc) rownames(ttrc) <- ttrc$Date ttrc$Date <- NULL input <- list( all=ttrc[1:250,], top=ttrc[1:250,], mid=ttrc[1:250,] ) input$top[1:10,] <- NA input$mid[9:20,] <- NA # Load output data load(system.file("tinytest/output/oscillators.rda", package="TTR")) ################################################# # MACD expect_equal( MACD(input$all$Close), output$allMACD ) expect_equal( attributes(MACD(input$all$Close)), attributes(output$allMACD) ) expect_equal( MACD(input$top$Close), output$topMACD ) expect_equal( attributes(MACD(input$top$Close)), attributes(output$topMACD) ) expect_error( MACD(input$mid$Close) ) # Stochastics # This mess is because data.frames' attributes don't come through reclass() well ia <- as.matrix(input$all[,c('High','Low','Close')]) it <- as.matrix(input$top[,c('High','Low','Close')]) #rn <- rownames(ia) #rownames(ia) <- rownames(it) <- NULL oa <- stoch(ia); #rownames(oa) <- rn ot <- stoch(it); #rownames(ot) <- rn # End: mess expect_equal( oa, output$allStoch ) expect_equal( attributes(oa), attributes(output$allStoch) ) expect_equal( ot, output$topStoch ) expect_equal( attributes(ot), attributes(output$topStoch) ) expect_error( stoch(input$mid[,c('High','Low','Close')]) ) a <- c(53.99, 54.69, rep(55.55, 3), rep(52.5, 13), rep(51.77, 2)) idx <- structure(1446422400 + cumsum(c(0, rep(86400, 4), 259200, rep(86400, 4), 259200, rep(86400,4), 259200, rep(86400, 2), 172800, 259200)), tzone = "UTC", tclass = "Date") X <- structure(c(a, a, a+0.1), .Dim = c(20L, 3L), class = c("xts", "zoo"), index = idx, .Dimnames = list(NULL, c("High", "Low", "Close"))) o <- structure(c(rep(NA, 9), rep(0.0327868852459021, 5), rep(0.5, 4), rep(0.136986301369856, 2), rep(NA, 11), rep(0.0327868852459021, 3), 0.188524590163935, 0.344262295081967, 0.5, 0.5, 0.378995433789952, 0.257990867579904, rep(NA, 13), 0.0327868852459021, 0.084699453551913, 0.188524590163935, 0.344262295081967, 0.448087431693989, 0.459665144596651, 0.378995433789952), .Dim = c(20L, 3L), .Dimnames = list(NULL, c("fastK", "fastD", "slowD")), index = idx, class = c("xts", "zoo")) s <- TTR::stoch(X, 10, 3) expect_equal(s, o, info = "handle Inf fastK") # TODO: delete line above after xts is released w/fix for #322 #expect_equal(s, o # Stochastic Momentum Index expect_equal( SMI(input$all[,c('High','Low','Close')]), output$allSMI ) expect_equal( attributes(SMI(input$all[,c('High','Low','Close')])), attributes(output$allSMI) ) expect_equal( SMI(input$top[,c('High','Low','Close')]), output$topSMI ) expect_equal( attributes(SMI(input$top[,c('High','Low','Close')])), attributes(output$topSMI) ) expect_error( SMI(input$mid[,c('High','Low','Close')]) ) # Relative Strength Index expect_equal( RSI(input$all$Close), output$allRSI ) expect_equal( attributes(RSI(input$all$Close)), attributes(output$allRSI) ) expect_equal( RSI(input$top$Close), output$topRSI ) expect_equal( attributes(RSI(input$top$Close)), attributes(output$topRSI) ) expect_error( RSI(input$mid$Close) ) wilder.and.matype <- RSI(input$all$Close, maType = "EMA", wilder = FALSE) wilder.only <- RSI(input$all$Close, wilder = FALSE) expect_equal( wilder.and.matype, wilder.only, info = "RSI does not overwrite maArgs") # Chande Momentum Oscillator expect_equal( CMO(input$all$Close), output$allCMO ) expect_equal( attributes(CMO(input$all$Close)), attributes(output$allCMO) ) expect_equal( CMO(input$top$Close), output$topCMO ) expect_equal( attributes(CMO(input$top$Close)), attributes(output$topCMO) ) expect_error( CMO(input$mid$Close) ) # De-trended Price Oscillator expect_equal( DPO(input$all$Close), output$allDPO ) expect_equal( attributes(DPO(input$all$Close)), attributes(output$allDPO) ) expect_equal( DPO(input$top$Close), output$topDPO ) expect_equal( attributes(DPO(input$top$Close)), attributes(output$topDPO) ) expect_error( DPO(input$mid$Close) ) # TRIX expect_equal( TRIX(input$all$Close), output$allTRIX ) expect_equal( attributes(TRIX(input$all$Close)), attributes(output$allTRIX) ) expect_equal( TRIX(input$top$Close), output$topTRIX ) expect_equal( attributes(TRIX(input$top$Close)), attributes(output$topTRIX) ) expect_error( TRIX(input$mid$Close) ) # Willams' Percent R # This mess is because data.frames' attributes don't come through reclass() well ia <- input$all[,c('High','Low','Close')] it <- input$top[,c('High','Low','Close')] rn <- rownames(ia) rownames(ia) <- rownames(it) <- NULL oa <- WPR(ia); names(oa) <- rn ot <- WPR(it); names(ot) <- rn # End: mess expect_equal( oa, output$allWPR ) expect_equal( attributes(oa), attributes(output$allWPR) ) expect_equal( ot, output$topWPR ) expect_equal( attributes(ot), attributes(output$topWPR) ) expect_error( WPR(input$mid$Close) ) # Ultimate Oscillator # This mess is because data.frames' attributes don't come through reclass() well ia <- input$all[,c('High','Low','Close')] it <- input$top[,c('High','Low','Close')] rn <- rownames(ia) rownames(ia) <- rownames(it) <- NULL oa <- ultimateOscillator(ia); names(oa) <- rn ot <- ultimateOscillator(it); names(ot) <- rn # End: mess expect_equal( oa, output$allUltOsc ) expect_equal( attributes(oa), attributes(output$allUltOsc) ) expect_equal( ot, output$topUltOsc ) expect_equal( attributes(ot), attributes(output$topUltOsc) ) expect_error( ultimateOscillator(input$mid$Close) ) # Ultimate Oscillator on non-xts monthly data iam <- xts::to.monthly(input$all, name=NULL)[,c('High','Low','Close')] rn <- rownames(iam) rownames(iam) <- NULL oam <- ultimateOscillator(iam, c(2,5,8)) # Ultimate Oscillator on xts monthly data xia <- xts::as.xts(input$all) xiam <- xts::to.monthly(xia, name=NULL)[,c('High','Low','Close')] xoam <- ultimateOscillator(xiam, c(2,5,8)) expect_equal( oam, as.numeric(xoam) ) ================================================ FILE: inst/tinytest/test-overlays.R ================================================ # Create input data data(ttrc) rownames(ttrc) <- ttrc$Date ttrc$Date <- NULL input <- list( all=ttrc[1:250,], top=ttrc[1:250,], mid=ttrc[1:250,] ) input$top[1:10,] <- NA input$mid[9:20,] <- NA # Load output data load(system.file("tinytest/output/overlays.rda", package="TTR")) ################################################# # Bollinger Bands ia <- input$all[,c('High','Low','Close')] it <- input$top[,c('High','Low','Close')] im <- input$mid[,c('High','Low')] rownames(ia) <- rownames(it) <- NULL oa <- BBands(ia) ot <- BBands(it) rownames(oa) <- rownames(ot) <- rownames(input$all) expect_equal( oa, output$allBBands ) expect_equal( attributes(oa), attributes(output$allBBands) ) expect_equal( ot, output$topBBands ) expect_equal( attributes(ot), attributes(output$topBBands) ) expect_error( BBands(im) ) # SAR ia <- input$all[,c('High','Low')] it <- input$top[,c('High','Low')] im <- input$mid[,c('High','Low')] rownames(ia) <- rownames(it) <- rownames(im) <- NULL expect_equal( SAR(ia), output$allSAR ) expect_equal( attributes(SAR(ia)), attributes(output$allSAR) ) expect_equal( SAR(it), output$topSAR ) expect_equal( attributes(SAR(it)), attributes(output$topSAR) ) expect_error( SAR(im) ) # Zig Zag ia <- input$all[,c('High','Low')] it <- input$top[,c('High','Low')] im <- input$mid[,c('High','Low')] rownames(ia) <- rownames(it) <- rownames(im) <- NULL expect_equal( ZigZag(ia), output$allZZ ) expect_equal( attributes(ZigZag(ia)), attributes(output$allZZ) ) expect_equal( ZigZag(it), output$topZZ ) expect_equal( attributes(ZigZag(it)), attributes(output$topZZ) ) expect_error( ZigZag(im) ) ================================================ FILE: inst/tinytest/test-runfun.R ================================================ # Create input data data(ttrc) rownames(ttrc) <- ttrc$Date ttrc$Date <- NULL input <- list( all=ttrc[1:250,], top=ttrc[1:250,], mid=ttrc[1:250,] ) input$top[1:10,] <- NA input$mid[9:20,] <- NA # Load output data load(system.file("tinytest/output/running-functions.rda", package="TTR")) ################################################# # Sum expect_equal( runSum(input$all$Close), output$allSum ) expect_equal( attributes(runSum(input$all$Close)), attributes(output$allSum) ) expect_equal( runSum(input$top$Close), output$topSum ) expect_equal( attributes(runSum(input$top$Close)), attributes(output$topSum) ) expect_error( runSum(input$mid$Close) ) expect_error( runSum(input$all[,1:2]) ) expect_equal( tail(runSum(input$all$Close,250),1), sum(input$all$Close) ) expect_error( runSum(input$all$Close, n = -1) ) expect_error( runSum(input$all$Close, n = NROW(input$all) + 1) ) # Wilder Sum expect_equal( wilderSum(input$all$Close), output$allwSum ) expect_equal( attributes(wilderSum(input$all$Close)), attributes(output$allwSum) ) expect_equal( wilderSum(input$top$Close), output$topwSum ) expect_equal( attributes(wilderSum(input$top$Close)), attributes(output$topwSum) ) expect_error( wilderSum(input$mid$Close) ) expect_error( wilderSum(input$all[,1:2]) ) expect_error( wilderSum(input$all$Close, n = -1) ) expect_error( wilderSum(input$all$Close, n = NROW(input$all) + 1) ) # Min expect_equal( runMin(input$all$Close), output$allMin ) expect_equal( attributes(runMin(input$all$Close)), attributes(output$allMin) ) expect_equal( runMin(input$top$Close), output$topMin ) expect_equal( attributes(runMin(input$top$Close)), attributes(output$topMin) ) expect_error( runMin(input$mid$Close) ) expect_error( runMin(input$all[,1:2]) ) expect_error( runMin(input$all$Close, n = -1) ) expect_error( runMin(input$all$Close, n = NROW(input$all) + 1) ) expect_equal( tail(runMin(input$all$Close,250),1), min(input$all$Close) ) ttr <- runMin(input$all$Close, 1, TRUE) base <- cummin(input$all$Close) expect_equal(base, ttr) # Max expect_equal( runMax(input$all$Close), output$allMax ) expect_equal( attributes(runMax(input$all$Close)), attributes(output$allMax) ) expect_equal( runMax(input$top$Close), output$topMax ) expect_equal( attributes(runMax(input$top$Close)), attributes(output$topMax) ) expect_error( runMax(input$mid$Close) ) expect_error( runMax(input$all[,1:2]) ) expect_error( runMax(input$all$Close, n = -1) ) expect_error( runMax(input$all$Close, n = NROW(input$all) + 1) ) expect_equal( tail(runMax(input$all$Close,250),1), max(input$all$Close) ) ttr <- runMax(input$all$Close, 1, TRUE) base <- cummax(input$all$Close) expect_equal(base, ttr) # Mean expect_equal( runMean(input$all$Close), output$allMean ) expect_equal( attributes(runMean(input$all$Close)), attributes(output$allMean) ) expect_equal( runMean(input$top$Close), output$topMean ) expect_equal( attributes(runMean(input$top$Close)), attributes(output$topMean) ) expect_error( runMean(input$mid$Close) ) expect_error( runMean(input$all[,1:2]) ) expect_error( runMean(input$all$Close, n = -1) ) expect_error( runMean(input$all$Close, n = NROW(input$all) + 1) ) expect_equal( tail(runMean(input$all$Close,250),1), mean(input$all$Close) ) ttr <- runMean(input$all$Close, 5, TRUE) base <- cumsum(input$all$Close) / seq_along(input$all$Close) is.na(base) <- 1:4 expect_equal(base, ttr) n.1.cumul <- runMean(1, n = 1, cumulative = TRUE) n.1.noncumul <- runMean(1, n = 1, cumulative = FALSE) expect_equal(n.1.cumul, n.1.noncumul, info = "cumulative n = 1") x <- c(rep(NA_real_, 5), 1:5) target <- c(rep(NA_real_, 5), cumsum(1:5) / 1:5) result <- runMean(x, n = 1, cumulative = TRUE) expect_equal(target, result, info = "cumulative accounts for leading NA") # Median expect_equal( runMedian(input$all$Close), output$allMedian ) expect_equal( attributes(runMedian(input$all$Close)), attributes(output$allMedian) ) expect_equal( runMedian(input$top$Close), output$topMedian ) expect_equal( attributes(runMedian(input$top$Close)), attributes(output$topMedian) ) expect_error( runMedian(input$mid$Close) ) expect_error( runMedian(input$all[,1:2]) ) expect_error( runMedian(input$all$Close, n = -1) ) expect_error( runMedian(input$all$Close, n = NROW(input$all) + 1) ) expect_equal( tail(runMedian(input$all$Close,250),1), median(input$all$Close) ) cummedian <- compiler::cmpfun( function(x) { med <- x * NA_real_ for (i in seq_along(x)) { med[i] <- median(x[1:i]) } med } ) base <- cummedian(input$all$Close) is.na(base) <- 1:4 ttr <- runMedian(input$all$Close, 5, "mean", TRUE) expect_equal(base, ttr) is.na(base) <- 1:5 ttr <- runMedian(input$all$Close, 6, "mean", TRUE) expect_equal(base, ttr) na <- rep(NA, 10) x <- input$all$Close xmed <- runMedian(x, 1, "mean", TRUE) y <- c(na, input$all$Close) ymed <- runMedian(y, 1, "mean", TRUE) expect_equal(ymed, c(na, xmed), info = "cumulative n = 1") n.1.cumul <- runMedian(1, n = 1, cumulative = TRUE) n.1.noncumul <- runMedian(1, n = 1, cumulative = FALSE) expect_equal(n.1.cumul, n.1.noncumul, info = "cumulative accounts for leading NA") # Covariance expect_equal( runCov(input$all$High, input$all$Low), output$allCov ) expect_equal( attributes(runCov(input$all$High, input$all$Low)), attributes(output$allCov) ) expect_equal( runCov(input$top$High, input$top$Low), output$topCov ) expect_equal( attributes(runCov(input$top$High, input$top$Low)), attributes(output$topCov) ) expect_error( runCov(input$mid$High, input$mid$Low) ) expect_error( runCov(input$all$High) ) expect_error( runCov(input$all[,1:2], input$all$Low) ) expect_error( runCov(input$all$Close, n = -1) ) expect_error( runCov(input$all$Close, n = NROW(input$all) + 1) ) expect_equal( tail(runCov(input$all$High, input$all$Low, 250),1), cov(input$all$High, input$all$Low) ) # x argument as xts object xhi <- xts::as.xts(input$all)$High xlo <- xts::as.xts(input$all)$Low expect_equal( as.numeric(runCov(xhi, input$all$Low)), output$allCov ) # x and y arguments as xts objects expect_equal( as.numeric(runCov(xhi, xlo)), output$allCov ) top <- input$top$Close mid <- input$mid$Close expect_error(runCov(top, mid)) expect_warning(runCov(1:10, 1:10, n = 1, cumulative = FALSE), info = "n = 1 and cumulative = FALSE throws warning") cumcov <- compiler::cmpfun( function(x) { cov <- x * NA_real_ for (i in seq_along(x)) { y <- x[1:i] cov[i] <- cov(y, y) } cov } ) x <- input$all$Close base <- cumcov(x) is.na(base) <- 1 ttr <- runCov(x, x, 1, "all.obs", TRUE, TRUE) expect_equal(base, ttr) is.na(base) <- 1:4 ttr <- runCov(x, x, 5, "all.obs", TRUE, TRUE) expect_equal(base, ttr) is.na(base) <- 1:5 ttr <- runCov(x, x, 6, "all.obs", TRUE, TRUE) expect_equal(base, ttr) # Correlation expect_equal( runCor(input$all$High, input$all$Low), output$allCor ) expect_equal( attributes(runCor(input$all$High, input$all$Low)), attributes(output$allCor) ) expect_equal( runCor(input$top$High, input$top$Low), output$topCor ) expect_equal( attributes(runCor(input$top$High, input$top$Low)), attributes(output$topCor) ) expect_error( runCor(input$mid$High, input$mid$Low) ) expect_error( runCor(input$all$High) ) expect_error( runCor(input$all[,1:2], input$all$Low) ) expect_error( runCor(input$all$Close, n = -1) ) expect_error( runCor(input$all$Close, n = NROW(input$all) + 1) ) expect_equal( tail(runCor(input$all$High, input$all$Low, 250),1), cor(input$all$High, input$all$Low) ) # Variance expect_equal( runVar(input$all$Close), output$allVar ) expect_equal( attributes(runVar(input$all$Close)), attributes(output$allVar) ) expect_equal( runVar(input$top$Close), output$topVar ) expect_equal( attributes(runVar(input$top$Close)), attributes(output$topVar) ) expect_error( runVar(input$mid$Close) ) expect_error( runVar(input$all[,1:2], input$all$Low) ) expect_error( runVar(input$all$Close, n = -1) ) expect_error( runVar(input$all$Close, n = NROW(input$all) + 1) ) expect_equal( tail(runVar(input$all$Close,n=250),1), var(input$all$Close) ) # Standard Deviation expect_equal( runSD(input$all$Close), output$allSD ) expect_equal( attributes(runSD(input$all$Close)), attributes(output$allSD) ) expect_equal( runSD(input$top$Close), output$topSD ) expect_equal( attributes(runSD(input$top$Close)), attributes(output$topSD) ) expect_error( runSD(input$mid$Close) ) expect_error( runSD(input$all[,1:2]) ) expect_error( runSD(input$all$Close, n = -1) ) expect_error( runSD(input$all$Close, n = NROW(input$all) + 1) ) expect_equal( tail(runSD(input$all$Close,250),1), sd(input$all$Close) ) x <- c(rep(NA_real_, 5), 1:5) target <- sapply(1:5, function(i) sd(seq_len(i))) target <- c(rep(NA, 5), target) result <- runSD(x, n = 1, cumulative = TRUE) expect_equal(target, result) # Absolute deviation expect_equal( runMAD(input$all$Close), output$allMAD ) expect_equal( attributes(runMAD(input$all$Close)), attributes(output$allMAD) ) expect_equal( runMAD(input$top$Close), output$topMAD ) expect_equal( attributes(runMAD(input$top$Close)), attributes(output$topMAD) ) expect_error( runMAD(input$mid$Close) ) expect_error( runMAD(input$all[,1:2]) ) expect_error( runMAD(input$all$Close, n = -1) ) expect_error( runMAD(input$all$Close, n = NROW(input$all) + 1) ) expect_equal( tail(runMAD(input$all$Close,250),1), mad(input$all$Close) ) cummad <- compiler::cmpfun( function(x) { mad <- x * NA_real_ for (i in seq_along(x)) { y <- x[1:i] mad[i] <- mad(y) } mad } ) x <- input$all$Close base <- cummad(x) is.na(base) <- 1:4 ttr <- runMAD(x, 5, cumulative = TRUE) expect_equal(base, ttr) is.na(base) <- 1:5 ttr <- runMAD(x, 6, cumulative = TRUE) expect_equal(base, ttr) na <- rep(NA, 10) x <- input$all$Close xmed <- runMAD(x, 1, cumulative = TRUE) y <- c(na, input$all$Close) ymed <- runMAD(y, 1, cumulative = TRUE) expect_equal(ymed, c(na, xmed)) # Percent Rank x <- input$all$Close expect_error( runPercentRank(x, 10, exact.multiplier = -0.1), info = "exact.multiplier bounds" ) expect_error( runPercentRank(x, 10, exact.multiplier = 1.1), info = "exact.multiplier bounds" ) xdata <- c(7.9, 5.2, 17.5, -12.7, 22, 4.3, -15.7, -9.3, 0.6, 0, -22.8, 7.6, -5.5, 1.7, 5.6, 15.1, 6.6, 11.2, -7.8, -4.3) xrank10_1 <- c(NA, NA, NA, NA, NA, NA, NA, NA, NA, 0.4, 0.1, 0.8, 0.5, 0.7, 0.9, 1, 0.8, 0.9, 0.2, 0.4) xrank10_0 <- c(NA, NA, NA, NA, NA, NA, NA, NA, NA, 0.3, 0, 0.7, 0.4, 0.6, 0.8, 0.9, 0.7, 0.8, 0.1, 0.3) xrank <- round(xrank10_0, 2) expect_identical(xrank, runPercentRank(xdata, 10, FALSE, 0), info = "exact.multiplier = 0") xrank <- round(xrank10_0 + 0.05, 2) expect_identical(xrank, runPercentRank(xdata, 10, FALSE, 0.5), info = "exact.multiplier = 0.5") xrank <- round(xrank10_0 + 0.1, 2) expect_identical(xrank, runPercentRank(xdata, 10, FALSE, 1), info = "exact.multiplier = 1") xrank <- c(0, 0, 2, 0, 4, 1, 0, 2, 3, 3, 0, 8, 4, 7, 10, 13, 11, 14, 4, 6) / 1:20 xrank[1:9] <- NA xrank[10] <- 0 expect_identical(xrank, runPercentRank(xdata, 10, TRUE, 0), info = "exact.multiplier = 0, cumulative = TRUE") xrank <- (c(0, 0, 2, 0, 4, 1, 0, 2, 3, 3, 0, 8, 4, 7, 10, 13, 11, 14, 4, 6) + 0.5) / 1:20 xrank[1:9] <- NA xrank[10] <- 0.5 expect_identical(xrank, runPercentRank(xdata, 10, TRUE, 0.5), info = "exact.multiplier = 0.5, cumulative = TRUE") xrank <- (c(0, 0, 2, 0, 4, 1, 0, 2, 3, 3, 0, 8, 4, 7, 10, 13, 11, 14, 4, 6) + 1) / 1:20 xrank[1:9] <- NA xrank[10] <- 1 expect_identical(xrank, runPercentRank(xdata, 10, TRUE, 1), info = "exact.multiplier = 1, cumulative = TRUE") ================================================ FILE: inst/tinytest/test-trend.R ================================================ # Create input data data(ttrc) rownames(ttrc) <- ttrc$Date ttrc$Date <- NULL iAll <- as.matrix(ttrc[1:250,]) iTop <- iAll; iTop[1:10,] <- NA iMid <- iAll; iMid[9:20,] <- NA hl <- c('High','Low') hlc <- c('High','Low','Close') cl <- 'Close' # Load output data load(system.file("tinytest/output/trend.rda", package="TTR")) ################################################# # ADX expect_equal( ADX(iAll[,hlc]), output$allADX ) expect_equal( attributes(ADX(iAll[,hlc])), attributes(output$allADX) ) expect_equal( ADX(iTop[,hlc]), output$topADX ) expect_equal( attributes(ADX(iTop[,hlc])), attributes(output$topADX) ) #expect_error( ADX(iMid[,hlc]) ) wilder.and.matype <- ADX(iAll[,hlc], maType = "EMA", wilder = FALSE) wilder.only <- ADX(iAll[,hlc], wilder = FALSE) expect_equal( wilder.and.matype, wilder.only, info = "ADX does not overwrite maArgs" ) # Aroon # non-xts ia <- iAll[,hl] it <- iTop[,hl] im <- iMid[,hl] rownames(ia) <- rownames(it) <- rownames(im) <- NULL oa <- aroon(ia); rownames(oa) <- rownames(iAll) ot <- aroon(it); rownames(ot) <- rownames(iTop) expect_equal( oa, output$allAroon ) expect_equal( attributes(oa), attributes(output$allAroon) ) expect_equal( ot, output$topAroon ) expect_equal( attributes(ot), attributes(output$topAroon) ) #expect_error( aroon(im) ) # xts expect_equal( aroon(iAll[,hl]), output$allAroon ) expect_equal( attributes(aroon(iAll[,hl])), attributes(output$allAroon) ) expect_equal( aroon(iTop[,hl]), output$topAroon ) expect_equal( attributes(aroon(iTop[,hl])), attributes(output$topAroon) ) #expect_error( aroon(iMid[,hl]) ) x <- c(NA, rnorm(10)) expect_silent(aroon(x, 10), info = "non-na equals 'n' does not error") # Average True Range # non-xts ia <- iAll[,hlc] it <- iTop[,hlc] im <- iMid[,hlc] rownames(ia) <- rownames(it) <- rownames(im) <- NULL aATR <- ATR(ia); rownames(aATR) <- rownames(iAll) tATR <- ATR(it); rownames(tATR) <- rownames(iTop) expect_equal( aATR, output$allATR ) expect_equal( attributes(aATR), attributes(output$allATR) ) expect_equal( tATR, output$topATR ) expect_equal( attributes(tATR), attributes(output$topATR) ) #expect_error( ATR(im) ) # xts expect_equal( ATR(iAll[,hlc]), output$allATR ) expect_equal( attributes(ATR(iAll[,hlc])), attributes(output$allATR) ) expect_equal( ATR(iTop[,hlc]), output$topATR ) expect_equal( attributes(ATR(iTop[,hlc])), attributes(output$topATR) ) #expect_error( ATR(iMid[,hlc]) ) wilder.and.matype <- ATR(iAll[,hlc], maType = "EMA", wilder = FALSE) wilder.only <- ATR(iAll[,hlc], wilder = FALSE) expect_equal( wilder.and.matype, wilder.only, info = "ATR does not overwrite maArgs" ) # Commodity Channel Index expect_equal( CCI(iAll[,hlc]), output$allCCI ) expect_equal( attributes(CCI(iAll[,hlc])), attributes(output$allCCI) ) expect_equal( CCI(iTop[,hlc]), output$topCCI ) expect_equal( attributes(CCI(iTop[,hlc])), attributes(output$topCCI) ) #expect_error( CCI(input$mid[,c('High','Low','Close')]) ) # Trend Detection Index ia <- iAll[,cl] it <- iTop[,cl] names(ia) <- names(it) <- NULL expect_equal( TDI(ia), output$allTDI ) expect_equal( attributes(TDI(ia)), attributes(output$allTDI) ) #expect_equal( TDI(iTop[,cl]), output$topTDI ) #expect_error( TDI(iMid[,cl]) ) # Vertical Horizontal Filter ia <- iAll[,cl] it <- iTop[,cl] names(ia) <- names(it) <- NULL expect_equal( VHF(ia), output$allVHF ) expect_equal( attributes(VHF(ia)), attributes(output$allVHF) ) #expect_equal( VHF(iTop[,cl]), output$topVHF ) #expect_error( VHF(iMid[,cl] ) ================================================ FILE: inst/tinytest/test-volatility.R ================================================ # Create input data data(ttrc) rownames(ttrc) <- ttrc$Date ttrc$Date <- NULL input <- list( all=ttrc[1:250,], top=ttrc[1:250,], mid=ttrc[1:250,] ) input$top[1:10,] <- NA input$mid[9:20,] <- NA # Load output data load(system.file("tinytest/output/volatility.rda", package="TTR")) ################################################# # Close # Why does the last two checks fail if they're first??? #expect_equal( volatility(input$all[,c('Open','High','Low','Close')],calc='close'), output$allClose ) #expect_equal( volatility(input$top[,c('Open','High','Low','Close')],calc='close'), output$topClose ) expect_error( volatility(input$mid[,c('Open','High','Low','Close')],calc='close') ) # Garman Klass ohlc <- c('Open','High','Low','Close') expect_equal( volatility(input$all[,ohlc],calc='garman.klass')[["x"]], output$allGK[["x"]] ) expect_equal( volatility(input$top[,ohlc],calc='garman.klass')[["x"]], output$topGK[["x"]] ) expect_error( volatility(input$mid[,ohlc],calc='garman.klass') ) # Parkinson ohlc <- c('Open','High','Low','Close') expect_equal( volatility(input$all[,ohlc],calc='parkinson')[["x"]], output$allParkinson[["x"]] ) expect_equal( volatility(input$top[,ohlc],calc='parkinson')[["x"]], output$topParkinson[["x"]] ) expect_error( volatility(input$mid[,ohlc],calc='parkinson') ) # Rogers Satchell ohlc <- c('Open','High','Low','Close') expect_equal( volatility(input$all[,ohlc],calc='rogers.satchell')[["x"]], output$allRS[["x"]] ) expect_equal( volatility(input$top[,ohlc],calc='rogers.satchell')[["x"]], output$topRS[["x"]] ) expect_error( volatility(input$mid[,ohlc],calc='rogers.satchell') ) # Chaikin Volatility ia <- as.matrix(input$all) rownames(ia) <- NULL expect_equal( chaikinVolatility(ia[,c('High','Low')]), output$allChaikin ) #expect_equal( chaikinVolatility(input$top[,c('Open','High','Low','Close')],calc='rogers.satchell'), output$topRS ) #expect_error( volatility(input$mid[,c('Open','High','Low','Close')],calc='rogers.satchell') ) ================================================ FILE: inst/tinytest/test-volume.R ================================================ # Create input data data(ttrc) rownames(ttrc) <- ttrc$Date ttrc$Date <- NULL #input <- list( all=ttrc[1:250,], top=ttrc[1:250,], mid=ttrc[1:250,] ) #input$top[1:10,] <- NA #input$mid[9:20,] <- NA #iAll <- as.matrix(ttrc[1:250,]) iAll <- ttrc[1:250,] iTop <- iAll; iTop[1:10,] <- NA iMid <- iAll; iMid[9:20,] <- NA hl <- c('High','Low') hlc <- c('High','Low','Close') cl <- 'Close' # Load output data load(system.file("tinytest/output/volume.rda", package="TTR")) ################################################# # On Balance Volume expect_equal( OBV(iAll$Close, iAll$Volume), output$allOBV ) #expect_equal( OBV(iTop[,cl], iTop[,'Volume']), output$topOBV ) #expect_error( OBV(iMid[,cl], iMid[,'Volume']) ) #expect_error( OBV(iAll[,cl], iMid[,'Volume']) ) #expect_error( OBV(iMid[,cl], iAll[,'Volume']) ) # Chaikin Accumulation / Distribution chAD <- chaikinAD(iAll[,hlc], iAll[,'Volume']) expect_equivalent( chaikinAD(iAll[,hlc], iAll[,'Volume']), output$allChaikinAD ) #expect_equal( chaikinAD(iTop[,hlc], iTop[,'Volume']), output$topChaikinAD ) #expect_error( chaikinAD(iMid[,hlc], iMid[,'Volume']) ) #expect_error( chaikinAD(iAll[,hlc], iMid[,'Volume']) ) #expect_error( chaikinAD(iMid[,hlc], iAll[,'Volume']) ) # Chaikin Money Flow ia <- iAll[,hlc]; rownames(ia) <- NULL it <- iTop[,hlc]; rownames(it) <- NULL expect_equal( CMF(ia, iAll[,'Volume']), output$allCMF ) expect_equal( CMF(it, iTop[,'Volume']), output$topCMF ) expect_error( CMF(iMid[,hlc], iMid[,'Volume']) ) expect_error( CMF(iAll[,hlc], iMid[,'Volume']) ) expect_error( CMF(iMid[,hlc], iAll[,'Volume']) ) # Money Flow Index ia <- iAll[,hlc]; rownames(ia) <- NULL it <- iTop[,hlc]; rownames(it) <- NULL expect_equal( MFI(ia, iAll[,'Volume']), output$allMFI ) expect_equal( MFI(it, iTop[,'Volume']), output$topMFI ) expect_error( MFI(iMid[,hlc], iMid[,'Volume']) ) expect_error( MFI(iAll[,hlc], iMid[,'Volume']) ) expect_error( MFI(iMid[,hlc], iAll[,'Volume']) ) x <- structure(c(6284.19, 6284.19, 6284.19, 6284.19, 6284.19, 6285.22, 6285.96, 6287.54, 6287.84, 6287.89, 6288.95, 6284.19, 6284.19, 6284.19, 6284.19, 6284.19, 6283.98, 6284.20, 6285.54, 6286.71, 6286.58, 6286.75, 6284.19, 6284.19, 6284.19, 6284.19, 6284.19, 6284.46, 6285.54, 6287.47, 6286.92, 6286.82, 6288.95, 9171293400, 9171293400, 9171293400, 9171293400, 9171293400, 1650189487, 1796244384, 1864666606, 1845475611, 1831082797, 1918533018), .Dim = c(11L, 4L)) o <- c(NA, NA, NA, 50, 50, 100, 100, 100, 100, 66.95494, 67.27551) m <- MFI(x[,-4], x[,4], n = 3) expect_equal(m, o, info = "MFI when volume is unchanged") # Williams' Accumulation / Distribution # non-xts ia <- iAll[,hlc] it <- iTop[,hlc] im <- iMid[,hlc] rownames(ia) <- rownames(it) <- rownames(im) <- NULL expect_equal( williamsAD(ia), output$allWilliamsAD ) #expect_equal( williamsAD(iTop[,hlc]), output$topWilliamsAD ) #expect_error( williamsAD(iMid[,hlc]) ) ================================================ FILE: man/ADX.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/ADX.R \name{ADX} \alias{ADX} \alias{DI} \alias{DX} \title{Welles Wilder's Directional Movement Index} \usage{ ADX(HLC, n = 14, maType, ...) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices.} \item{n}{Number of periods to use for DX calculation (not ADX calculation).} \item{maType}{A function or a string naming the function to be called.} \item{\dots}{Other arguments to be passed to the \code{maType} function.} } \value{ A object of the same class as \code{HLC} or a matrix (if \code{try.xts} fails) containing the columns: \describe{ \item{ DIp }{ The positive Direction Index. } \item{ DIn }{ The negative Direction Index. } \item{ DX }{ The Direction Index. } \item{ ADX }{ The Average Direction Index (trend strength). } } } \description{ Directional Movement Index; developed by J. Welles Wilder. } \details{ The \code{DIp}/\code{DIn} (positive/negative) is the percentage of the true range that is up/down. } \note{ A buy/sell signal is generated when the +/-DI crosses up over the -/+DI, when the DX/ADX signals a strong trend. A high/low DX signals a strong/weak trend. DX is usually smoothed with a moving average (i.e. the ADX). } \examples{ data(ttrc) dmi.adx <- ADX(ttrc[,c("High","Low","Close")]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/DI.htm}\cr \url{https://www.fmlabs.com/reference/DX.htm}\cr \url{https://www.fmlabs.com/reference/ADX.htm}\cr \url{https://www.fmlabs.com/reference/ADXR.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=49}\cr \url{https://www.linnsoft.com/techind/directional-indicator-diplus-diminus}\cr \url{https://www.linnsoft.com/techind/adx-avg-directional-movement}\cr \url{https://www.linnsoft.com/techind/adxr-avg-directional-movement-rating}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:average_directional_index_adx}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. The DX calculation uses \code{\link{ATR}}. See \code{\link{aroon}}, \code{\link{CCI}}, \code{\link{TDI}}, \code{\link{VHF}}, \code{\link{GMMA}} for other indicators that measure trend direction/strength. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/ATR.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/ATR.R \name{TR} \alias{TR} \alias{ATR} \title{True Range / Average True Range} \usage{ TR(HLC) ATR(HLC, n = 14, maType, ...) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices.} \item{n}{Number of periods for moving average.} \item{maType}{A function or a string naming the function to be called.} \item{\dots}{Other arguments to be passed to the \code{maType} function.} } \value{ A object of the same class as \code{HLC} or a matrix (if \code{try.xts} fails) containing the columns: \describe{ \item{ tr }{ The true range of the series. } \item{ atr }{ The average (as specified by \code{ma}) true range of the series. } \item{ trueHigh }{ The true high of the series. } \item{ trueLow }{ The true low of the series. } } } \description{ True range (TR) is a measure of volatility of a High-Low-Close series; average true range (ATR) is a Welles Wilder's style moving average of the TR. Developed by J. Welles Wilder in 1978. } \details{ TR incorporates yesterday's close in the calculation (high minus low). E.g. if yesterday's close was higher than today's high, then the TR would equal yesterday's close minus today's low. The ATR is a component of the Welles Wilder Directional Movement Index (\code{DX}, \code{ADX}). } \examples{ data(ttrc) tr <- TR(ttrc[,c("High","Low","Close")]) atr <- ATR(ttrc[,c("High","Low","Close")], n=14) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/TR.htm}\cr \url{https://www.fmlabs.com/reference/ATR.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=35}\cr \url{https://www.linnsoft.com/techind/true-range-tr}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:average_true_range_atr}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. See \code{\link{DX}}, which uses true range. See \code{\link{chaikinVolatility}} for another volatility measure. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/CCI.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/CCI.R \name{CCI} \alias{CCI} \title{Commodity Channel Index} \usage{ CCI(HLC, n = 20, maType, c = 0.015, ...) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices. If only a univariate series is given, it will be used. See details.} \item{n}{Number of periods for moving average.} \item{maType}{A function or a string naming the function to be called.} \item{c}{Constant to apply to the mean deviation.} \item{\dots}{Other arguments to be passed to the \code{maType} function.} } \value{ A object of the same class as \code{HLC} or a vector (if \code{try.xts} fails) containing the CCI values. } \description{ The Commodity Channel Index (CCI) attempts to identify starting and ending trends. } \details{ CCI relates the current price and the average of price over \code{n} periods. The CCI usually falls in a channel of -100 to 100. A basic CCI trading system is: Buy (sell) if CCI rises above 100 (falls below -100) and sell (buy) when it falls below 100 (rises above -100). CCI is usually calculated using the typical price, but if a univariate series (e.g. Close, Weighted Close, Median Price, etc.) is provided, it will be used instead. } \note{ If \code{HLC} is a High-Low-Close matrix, then typical price will be calculated. If \code{HLC} is a vector, then those values will be used instead of the typical price. } \examples{ data(ttrc) cci <- CCI(ttrc[,c("High","Low","Close")]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/CCI.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=42}\cr \url{https://www.linnsoft.com/techind/cci-commodity-channel-index}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:commodity_channel_index_cci}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. See \code{\link{aroon}}, \code{\link{ADX}}, \code{\link{TDI}}, \code{\link{VHF}}, \code{\link{GMMA}} for other indicators that measure trend direction/strength. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/CLV.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/CLV.R \name{CLV} \alias{CLV} \title{Close Location Value} \usage{ CLV(HLC) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices.} } \value{ A object of the same class as \code{HLC} or a vector (if \code{try.xts} fails) containing the Close Location Values of a High-Low-Close price series. } \description{ The Close Location Value (CLV) relates the day's close to its trading range. } \details{ The CLV will fall in a range of -1 to +1. If the CLV is +/-1, the close is at the high/low; if the CLV is 0, the close is directly between the high and low. } \examples{ data(ttrc) clv <- CLV(ttrc[,c("High","Low","Close")]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line}\cr } \seealso{ See \code{\link{chaikinAD}}, which uses CLV. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/CMF.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/CMF.R \name{CMF} \alias{CMF} \title{Chaikin Money Flow} \usage{ CMF(HLC, volume, n = 20) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices.} \item{volume}{Vector or matrix of volume observations corresponding to the \code{HLC} object.} \item{n}{Number of periods to use.} } \value{ A object of the same class as \code{HLC} and \code{volume} or a vector (if \code{try.xts} fails) containing the Chaikin Money Flow values. } \description{ Chaikin Money Flow compares total volume over the last \code{n} time periods to total volume times the Close Location Value (CLV) over the last \code{n} time periods. Developed by Marc Chaikin. } \details{ Chaikin Money Flow is calculated by taking dividing the sum of the Chaikin Accumulation / Distribution line over the past \code{n} periods by the sum of volume over the past \code{n} periods. } \note{ When Chaikin Money Flow is above/below +/- 0.25 it is a bullish/bearish signal. If Chaikin Money Flow remains below zero while the price is rising, it indicates a probable reversal. } \examples{ data(ttrc) cmf <- CMF(ttrc[,c("High","Low","Close")], ttrc[,"Volume"]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/ChaikinMoneyFlow.htm}\cr \url{https://www.linnsoft.com/techind/chaikin-money-flow-cmf}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_money_flow_cmf}\cr } \seealso{ See \code{\link{CLV}}, and \code{\link{chaikinAD}}. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/CMO.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/CMO.R \name{CMO} \alias{CMO} \title{Chande Momentum Oscillator} \usage{ CMO(x, n = 14) } \arguments{ \item{x}{Price, volume, etc. series that is coercible to xts or matrix.} \item{n}{Number of periods to use.} } \value{ A object of the same class as \code{x} or a vector (if \code{try.xts} fails) containing Chande Momentum Oscillator values. } \description{ The Chande Momentum Oscillator (CMO) is a modified RSI. Developed by Tushar S. Chande. } \details{ The CMO divides the total movement by the net movement ([up - down] / [up + down]), where RSI divides the upward movement by the net movement (up / [up + down]). } \note{ There are several ways to interpret the CMO: \enumerate{ \item Values over/under +/- 50 indicate overbought/oversold conditions. \item High CMO values indicate strong trends. \item When the CMO crosses above/below a moving average of the CMO, it is a buy/sell signal. } } \examples{ data(ttrc) cmo <- CMO(ttrc[,"Close"]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/CMO.htm}\cr } \seealso{ See \code{\link{RSI}}. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/CTI.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/CTI.R \name{CTI} \alias{CTI} \title{Ehler's Correlation Trend Indicator} \usage{ CTI(price, n = 20, slope = 1) } \arguments{ \item{price}{Price series that is coercible to xts or matrix.} \item{n}{Number of periods to use.} \item{slope}{Slope of desired trend.} } \value{ A object of the same class as \code{price} or a matrix (if \code{try.xts} fails) with the column: \describe{ \item{cti}{ The Correlation Trend Indicator. } } } \description{ Ehler's Correlation Trend Indicator (CTI) measures the Spearman correlation of the price with the ideal trend line: a straight line with increasing slope. } \details{ The CTI measures the Spearman correlation between the price and the ideal trend line with slope of \code{slope}, over the past \code{n} days. See URL in references section for further details. } \note{ Positive/negative CTI values signal positive/negative correlation with the desired trend line slope. A simple strategy could be long when the CTI is positive and, short when it is negative. } \examples{ data(ttrc) cti <- CTI(ttrc[,"Close"], n = 20) } \references{ John Ehlers, Correlation Trend Indicator, Stocks & Commodities May-2020 The following site(s) were used to code/document this indicator:\cr \url{https://financial-hacker.com/petra-on-programming-a-unique-trend-indicator/}\cr } \seealso{ See \code{\link{aroon}}, \code{\link{CCI}}, \code{\link{ADX}}, \code{\link{VHF}}, \code{\link{GMMA}}, \code{\link{TDI}} for other indicators that measure trend direction/strength. } \author{ Ethan Smith, Joshua Ulrich } \keyword{ts} ================================================ FILE: man/DPO.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/DPO.R \name{DPO} \alias{DPO} \title{De-Trended Price Oscillator} \usage{ DPO(x, n = 10, maType, shift = n/2 + 1, percent = FALSE, ...) } \arguments{ \item{x}{Price, volume, etc. series that is coercible to xts or matrix.} \item{n}{Number of periods for moving average.} \item{maType}{A function or a string naming the function to be called.} \item{shift}{The number of periods to shift the moving average.} \item{percent}{logical; if \code{TRUE}, the percentage difference between the slow and fast moving averages is returned, otherwise the difference between the respective averages is returned.} \item{\dots}{Other arguments to be passed to the \code{maType} function.} } \value{ A object of the same class as \code{x} or a vector (if \code{try.xts} fails) containing the DPO values. } \description{ The Detrended Price Oscillator (DPO) removes the trend in prices - or other series - by subtracting a moving average of the price from the price. } \details{ The Detrended Price shows cycles and overbought / oversold conditions. } \note{ DPO does not extend to the last date because it is based on a displaced moving average. The calculation shifts the results \code{shift} periods, so the last \code{shift} periods will be zero.\cr As stated above, the DPO can be used on any univariate series, not just price. } \section{Warning}{ The detrended price oscillator removes the trend in the series by centering the moving average. Centering the moving average causes it to include future data. Therefore, even though this indicator looks like a classic oscillator, it should not be used for trading rule signals. } \examples{ data(ttrc) priceDPO <- DPO(ttrc[,"Close"]) volumeDPO <- DPO(ttrc[,"Volume"]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:detrended_price_osci}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. See \code{\link{MACD}} for a general oscillator. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/DVI.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/DVI.R \name{DVI} \alias{DVI} \title{DV Intermediate Oscillator} \usage{ DVI( price, n = 252, wts = c(0.8, 0.2), smooth = 3, magnitude = c(5, 100, 5), stretch = c(10, 100, 2), exact.multiplier = 1 ) } \arguments{ \item{price}{Price series that is coercible to xts or matrix.} \item{n}{Number of periods for the percent rank.} \item{wts}{The weight given to the smoothed returns (magnitude) component and the up/down days (stretch) component, respectively.} \item{smooth}{The number of periods to smooth price.} \item{magnitude}{A set of 3 periods used to smooth magnitude.} \item{stretch}{A set of 3 periods used to smooth stretch.} \item{exact.multiplier}{The weight applied to identical values in the window. See \code{runPercentRank}.} } \value{ A object of the same class as \code{price} or a vector (if \code{try.xts} fails) containing the DVI values. } \description{ The DV Intermediate oscillator (DVI) is a very smooth momentum oscillator that can also be used as a trend indicator. Created by David Varadi. } \details{ The DVI combines smoothed returns over different time windows and the relative number of up versus down days (stretch) over different time windows. } \examples{ data(ttrc) dvi <- DVI(ttrc[,"Close"]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://cssanalytics.wordpress.com/2009/12/13/what-is-the-dvi/}\cr \url{https://marketsci.wordpress.com/2010/07/27/css-analytics\%E2\%80\%99-dvi-indicator-revealed/}\cr } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/DonchianChannel.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/DonchianChannel.R \name{DonchianChannel} \alias{DonchianChannel} \alias{Donchian} \title{Donchian Channel} \usage{ DonchianChannel(HL, n = 10, include.lag = FALSE) } \arguments{ \item{HL}{Object that is coercible to xts or matrix and contains High-Low prices.} \item{n}{Number of periods for moving average.} \item{include.lag}{Should values be lagged so that today's prices are not included in the calculation? See Note.} } \value{ A object of the same class as \code{HL} or a matrix (if \code{try.xts} fails) containing the columns: \describe{ \item{ high }{ The highest high series. } \item{ mid }{ The average of \code{high} and \code{low}. } \item{ low }{ The lowest low series. } } } \description{ Donchian Channels were created by Richard Donchian and were used to generate buy and sell signals for the Turtle Trading system. } \details{ Donchian Channels consist of two (sometimes three) lines: The top line is the highest high of the past \code{n} periods. The bottom line is the lowest low of the past \code{n} periods. The middle line is the average of the top and bottom lines. } \note{ The default of \code{include.lag=FALSE} makes \code{DonchainChannel} consistent with other \pkg{TTR} functions, in that it includes the current period in the calculation. The default is different than the original calculation, which would calculate the indicator using periods t-1 through t-n. Setting \code{include.lag=TRUE} will return the result of the original calculation. The default of this argument may change in the future. } \examples{ data(ttrc) dc <- DonchianChannel( ttrc[,c("High","Low")] ) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.linnsoft.com/techind/donchian-channels}\cr } \seealso{ See \code{\link{BBands}}. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/EMV.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/EMV.R \name{EMV} \alias{EMV} \title{Arms' Ease of Movement Value} \usage{ EMV(HL, volume, n = 9, maType, vol.divisor = 10000, ...) } \arguments{ \item{HL}{Object that is coercible to xts or matrix and contains High-Low prices.} \item{volume}{Vector or matrix of volume observations corresponding to the \code{HL} object.} \item{n}{Number of periods for moving average.} \item{maType}{A function or a string naming the function to be called.} \item{vol.divisor}{An increment to make the results larger and easier to work with.} \item{\dots}{Other arguments to be passed to the \code{maType} function.} } \value{ A object of the same class as \code{HL} and \code{volume} or a matrix (if \code{try.xts} fails) containing the columns: \describe{ \item{ emv }{ The ease of movement values. } \item{ maEMV }{ The smoothed (as specified by \code{ma}) ease of movement values. } } } \description{ Arms' Ease of Movement Value (EMV) emphasizes days where the security moves easily and minimizes days where the security does not move easily. Developed by Richard W. Arms, Jr. } \details{ The EMV is calculated by dividing the midpoint ([high + low]/2) move by the 'Box Ratio' (volume divided by the high minus low). } \note{ A buy/sell signal is generated when the EMV crosses above/below zero. When the EMV hovers around zero, there are small price movements and/or high volume, and the price is not moving easily. } \examples{ data(ttrc) emv <- EMV(ttrc[,c("High","Low")], ttrc[,"Volume"]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/ArmsEMV.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=51}\cr \url{https://www.linnsoft.com/techind/arms-ease-movement}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/GMMA.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/GMMA.R \name{GMMA} \alias{GMMA} \alias{Guppy} \alias{guppy} \title{Guppy Multiple Moving Averages} \usage{ GMMA( x, short = c(3, 5, 8, 10, 12, 15), long = c(30, 35, 40, 45, 50, 60), maType ) } \arguments{ \item{x}{Price, volume, etc. series that is coercible to xts or matrix.} \item{short}{Vector of short-term periods.} \item{long}{Vector of long-term periods.} \item{maType}{Either: \enumerate{ \item A function or a string naming the function to be called. \item A \emph{list} with the first component like (1) above, and additional parameters specified as \emph{named} components. See Examples. }} } \value{ A object of the same class as \code{x} or \code{price} or a vector (if \code{try.xts} fails) containing the Guppy Multiple Moving Average. } \description{ Calculate the Guppy Multiple Moving Average of a series. } \details{ The Guppy Multiple Moving Average signals a changing trend when the \code{short} and \code{long} groups of moving averages intersect. An up/down trend exists when the short/long-term moving averages are greater than the long/short-term averages. } \examples{ data(ttrc) gmma <- GMMA(ttrc[,"Close"]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.investopedia.com/terms/g/guppy-multiple-moving-average.asp}\cr } \seealso{ See \code{\link{aroon}}, \code{\link{CCI}}, \code{\link{ADX}}, \code{\link{VHF}}, \code{\link{TDI}} for other indicators that measure trend direction/strength. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/KST.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/KST.R \name{KST} \alias{KST} \title{Know Sure Thing} \usage{ KST( price, n = c(10, 10, 10, 15), nROC = c(10, 15, 20, 30), nSig = 9, maType, wts = 1:NROW(n), ... ) } \arguments{ \item{price}{Price series that is coercible to xts or matrix.} \item{n}{A vector of the number of periods to use in the MA calculations.} \item{nROC}{A vector of the number of periods to use in the ROC calculations.} \item{nSig}{The number of periods to use for the KST signal line.} \item{maType}{Either: \enumerate{ \item A function or a string naming the function to be called. \item A \emph{list} with the first component like (1) above, and additional parameters specified as \emph{named} components. See Examples. }} \item{wts}{A vector the same length as \code{n}, of the weight for each period (need not sum to one).} \item{\dots}{Other arguments to be passed to the \code{maType} function in case (1) above.} } \value{ A object of the same class as \code{price} or a vector (if \code{try.xts} fails) containing the Know Sure Thing values. } \description{ The Know Sure Thing (KST) is a smooth, summed, rate of change indicator. Developed by Martin Pring. } \details{ For each day (week, month, etc.), the KST calculates the ROC over several periods. Those ROCs are smoothed using the given moving averages, then multiplied by their respective weighting values. The resulting values are summed for each day (month, week, etc.). } \note{ The KST indicates bullish/bearish momentum as it crosses above/below its moving average. Because the KST tends to lead price action, look for trend confirmation in the price. The default arguments are for the daily KST. There is also the Long-Term KST, with arguments: \code{n=c(9, 12, 18, 24)} - where the periods are months, not days - and the moving average periods are 6, 6, 6, and 9 months, respectively. } \examples{ data(ttrc) kst <- KST(ttrc[,"Close"]) kst4MA <- KST(ttrc[,"Close"], maType=list(list(SMA),list(EMA),list(DEMA),list(WMA))) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://web.archive.org/web/20110715112957/http://www.pring.com/movieweb/daily_kst.htm}\cr \url{https://web.archive.org/web/20100101162707/http://www.pring.com/movieweb/KST_MCM.htm}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. See \code{\link{ROC}} for the rate-of-change function. See \code{\link{MACD}} for a generic oscillator. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/MACD.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/MACD.R \name{MACD} \alias{MACD} \title{MACD Oscillator} \usage{ MACD(x, nFast = 12, nSlow = 26, nSig = 9, maType, percent = TRUE, ...) } \arguments{ \item{x}{Object that is coercible to xts or matrix; usually price, but can be volume, etc.} \item{nFast}{Number of periods for fast moving average.} \item{nSlow}{Number of periods for slow moving average.} \item{nSig}{Number of periods for signal moving average.} \item{maType}{Either: \enumerate{ \item A function or a string naming the function to be called. \item A \emph{list} with the first component like (1) above, and additional parameters specified as \emph{named} components. See Examples. }} \item{percent}{logical; if \code{TRUE}, the percentage difference between the fast and slow moving averages is returned, otherwise the difference between the respective averages is returned.} \item{\dots}{Other arguments to be passed to the \code{maType} function in case (1) above.} } \value{ A object of the same class as \code{x} or a matrix (if \code{try.xts} fails) containing the columns: \describe{ \item{ macd }{ The price (volume, etc.) oscillator. } \item{ signal }{ The oscillator signal line (a moving average of the oscillator). } } } \description{ The MACD was developed by Gerald Appel and is probably the most popular price oscillator. The MACD function documented in this page compares a fast moving average (MA) of a series with a slow MA of the same series. It can be used as a generic oscillator for any univariate series, not only price. } \details{ The MACD function either subtracts the fast MA from the slow MA, or finds the rate of change between the fast MA and the slow MA. } \note{ The MACD is a special case of the general oscillator applied to price. The MACD can be used as a general oscillator applied to any series. Time periods for the MACD are often given as 26 and 12, but the original formula used exponential constants of 0.075 and 0.15, which are closer to 25.6667 and 12.3333 periods. } \examples{ data(ttrc) macd <- MACD( ttrc[,"Close"], 12, 26, 9, maType="EMA" ) macd2 <- MACD( ttrc[,"Close"], 12, 26, 9, maType=list(list(SMA), list(EMA, wilder=TRUE), list(SMA)) ) } \references{ The following site(s) were used to code/document this indicator: \cr Moving Average Convergence/Divergence (MACD):\cr \url{https://www.fmlabs.com/reference/MACD.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=66}\cr \url{https://www.linnsoft.com/techind/macd}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:moving_average_convergence_divergence_macd}\cr \cr Price Oscillator:\cr \url{https://www.fmlabs.com/reference/PriceOscillator.htm}\cr \url{https://www.fmlabs.com/reference/PriceOscillatorPct.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=94}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:price_oscillators_ppo}\cr \cr Volume Oscillator:\cr \url{https://www.fmlabs.com/reference/PVO.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=122}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/MFI.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/MFI.R \name{MFI} \alias{MFI} \alias{moneyFlow} \title{Money Flow Index} \usage{ MFI(HLC, volume, n = 14) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices. If only a univariate series is given, it will be used. See details.} \item{volume}{Vector or matrix of volume observations corresponding to \code{HLC} object.} \item{n}{Number of periods to use.} } \value{ A object of the same class as \code{HLC} and \code{volume} or a vector (if \code{try.xts} fails) containing the MFI values. } \description{ The MFI is a ratio of positive and negative money flow over time. } \details{ Money Flow (MF) is the product of price and volume. Positive/negative MF occur when today's price is higher/lower than yesterday's price. The MFI is calculated by dividing positive MF by negative MF for the past \code{n} periods. It is then scaled between 0 and 100. MFI is usually calculated using the typical price, but if a univariate series (e.g. Close, Weighted Close, Median Price, etc.) is provided, it will be used instead. } \note{ Divergence between MFI and price can be indicative of a reversal. In addition, values above/below 80/20 indicate market tops/bottoms. } \examples{ data(ttrc) mfi <- MFI(ttrc[,c("High","Low","Close")], ttrc[,"Volume"]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/default.htm?url=MoneyFlowIndex.htm}\cr \url{https://www.linnsoft.com/techind/money-flow-index-mfi}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:money_flow_index_mfi}\cr } \seealso{ See \code{\link{OBV}} and \code{\link{CMF}}. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/MovingAverages.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/MovingAverages.R \name{SMA} \alias{SMA} \alias{MovingAverages} \alias{EMA} \alias{WMA} \alias{DEMA} \alias{GD} \alias{T3} \alias{EVWMA} \alias{ZLEMA} \alias{VWAP} \alias{VWMA} \alias{MA} \alias{HMA} \alias{ALMA} \title{Moving Averages} \usage{ SMA(x, n = 10, ...) EMA(x, n = 10, wilder = FALSE, ratio = NULL, ...) DEMA(x, n = 10, v = 1, wilder = FALSE, ratio = NULL) WMA(x, n = 10, wts = 1:n, ...) EVWMA(price, volume, n = 10, ...) ZLEMA(x, n = 10, ratio = NULL, ...) VWAP(price, volume, n = 10, ...) HMA(x, n = 20, ...) ALMA(x, n = 9, offset = 0.85, sigma = 6, ...) } \arguments{ \item{x}{Price, volume, etc. series that is coercible to xts or matrix.} \item{n}{Number of periods to average over. Must be between 1 and \code{nrow(x)}, inclusive.} \item{\dots}{any other passthrough parameters} \item{wilder}{logical; if \code{TRUE}, a Welles Wilder type EMA will be calculated; see notes.} \item{ratio}{A smoothing/decay ratio. \code{ratio} overrides \code{wilder} in \code{EMA}.} \item{v}{The 'volume factor' (a number in [0,1]). See Notes.} \item{wts}{Vector of weights. Length of \code{wts} vector must equal the length of \code{x}, or \code{n} (the default).} \item{price}{Price series that is coercible to xts or matrix.} \item{volume}{Volume series that is coercible to xts or matrix, that corresponds to price series, or a constant. See Notes.} \item{offset}{Percentile at which the center of the distribution should occur.} \item{sigma}{Standard deviation of the distribution.} } \value{ A object of the same class as \code{x} or \code{price} or a vector (if \code{try.xts} fails) containing the columns: \describe{ \item{SMA}{ Simple moving average. } \item{EMA}{ Exponential moving average. } \item{WMA}{ Weighted moving average. } \item{DEMA}{ Double-exponential moving average. } \item{EVWMA}{ Elastic, volume-weighted moving average. } \item{ZLEMA}{ Zero lag exponential moving average. } \item{VWMA}{ Volume-weighed moving average (same as \code{VWAP}). } \item{VWAP}{ Volume-weighed average price (same as \code{VWMA}). } \item{VWA}{ Variable-length moving average. } \item{HMA}{ Hull moving average. } \item{ALMA}{ Arnaud Legoux moving average. } } } \description{ Calculate various moving averages (MA) of a series. } \details{ \code{SMA} calculates the arithmetic mean of the series over the past \code{n} observations. \code{EMA} calculates an exponentially-weighted mean, giving more weight to recent observations. See Warning section below. \code{WMA} is similar to an EMA, but with linear weighting if the length of \code{wts} is equal to \code{n}. If the length of \code{wts} is equal to the length of \code{x}, the WMA will use the values of \code{wts} as weights. \code{DEMA} is calculated as: \code{DEMA = (1 + v) * EMA(x,n) - EMA(EMA(x,n),n) * v} (with the corresponding \code{wilder} and \code{ratio} arguments). \code{EVWMA} uses volume to define the period of the MA. \code{ZLEMA} is similar to an EMA, as it gives more weight to recent observations, but attempts to remove lag by subtracting data prior to \code{(n-1)/2} periods (default) to minimize the cumulative effect. \code{VWMA} and \code{VWAP} calculate the volume-weighted moving average price. \code{HMA} a WMA of the difference of two other WMAs, making it very reponsive. \code{ALMA} inspired by Gaussian filters. Tends to put less weight on most recent observations, reducing tendency to overshoot. } \note{ For \code{EMA}, \code{wilder=FALSE} (the default) uses an exponential smoothing ratio of \code{2/(n+1)}, while \code{wilder=TRUE} uses Welles Wilder's exponential smoothing ratio of \code{1/n}. The \code{EMA} result is initialized with the \code{n}-period sample average at period \code{n}. The exponential decay is applied from that point forward. Since \code{WMA} can accept a weight vector of length equal to the length of \code{x} or of length \code{n}, it can be used as a regular weighted moving average (in the case \code{wts=1:n}) or as a moving average weighted by volume, another indicator, etc. Since \code{DEMA} allows adjusting \code{v}, it is technically Tim Tillson's generalized DEMA (GD). When \code{v=1} (the default), the result is the standard DEMA. When \code{v=0}, the result is a regular EMA. All other values of \code{v} return the GD result. This function can be used to calculate Tillson's T3 indicator (see example below). Thanks to John Gavin for suggesting the generalization. For \code{EVWMA}, if \code{volume} is a series, \code{n} should be chosen so the sum of the volume for \code{n} periods approximates the total number of outstanding shares for the security being averaged. If \code{volume} is a constant, it should represent the total number of outstanding shares for the security being averaged. } \section{Warning }{ Some indicators (e.g. EMA, DEMA, EVWMA, etc.) are calculated using the indicators' own previous values, and are therefore unstable in the short-term. As the indicator receives more data, its output becomes more stable. See example below. } \examples{ data(ttrc) ema.20 <- EMA(ttrc[,"Close"], 20) sma.20 <- SMA(ttrc[,"Close"], 20) dema.20 <- DEMA(ttrc[,"Close"], 20) evwma.20 <- EVWMA(ttrc[,"Close"], ttrc[,"Volume"], 20) zlema.20 <- ZLEMA(ttrc[,"Close"], 20) alma <- ALMA(ttrc[,"Close"]) hma <- HMA(ttrc[,"Close"]) ## Example of Tim Tillson's T3 indicator T3 <- function(x, n=10, v=1) DEMA(DEMA(DEMA(x,n,v),n,v),n,v) t3 <- T3(ttrc[,"Close"]) ## Example of short-term instability of EMA ## (and other indicators mentioned above) x <- rnorm(100) tail( EMA(x[90:100],10), 1 ) tail( EMA(x[70:100],10), 1 ) tail( EMA(x[50:100],10), 1 ) tail( EMA(x[30:100],10), 1 ) tail( EMA(x[10:100],10), 1 ) tail( EMA(x[ 1:100],10), 1 ) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/ExpMA.htm}\cr \url{https://www.fmlabs.com/reference/WeightedMA.htm}\cr \url{https://www.fmlabs.com/reference/DEMA.htm}\cr \url{https://www.fmlabs.com/reference/T3.htm}\cr \url{https://www.linnsoft.com/techind/evwma-elastic-volume-weighted-moving-average}\cr \url{https://www.fmlabs.com/reference/ZeroLagExpMA.htm}\cr \url{https://www.fmlabs.com/reference/VIDYA.htm}\cr \url{https://www.traderslog.com/hullmovingaverage}\cr \url{https://web.archive.org/web/20180222085959/http://arnaudlegoux.com/}\cr } \seealso{ See \code{\link{wilderSum}}, which is used in calculating a Welles Wilder type MA. } \author{ Joshua Ulrich, Ivan Popivanov (HMA, ALMA) } \keyword{ts} ================================================ FILE: man/OBV.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/OBV.R \name{OBV} \alias{OBV} \title{On Balance Volume (OBV)} \usage{ OBV(price, volume) } \arguments{ \item{price}{Price series that is coercible to xts or matrix.} \item{volume}{Volume series that is coercible to xts or matrix, that corresponds to price object.} } \value{ A object of the same class as \code{price} and \code{volume} or a vector (if \code{try.xts} fails) containing the OBV values. } \description{ On Balance Volume (OBV) is a measure of the money flowing into or out of a security. It is similar to Chaikin Accumulation / Distribution. } \details{ OBV is calculated by adding (subtracting) each day's volume to a running cumulative total when the security's price closes higher (lower). } \note{ OBV is usually compared with the price chart of the underlying security to look for divergences/confirmation. } \examples{ data(ttrc) obv <- OBV(ttrc[,"Close"], ttrc[,"Volume"]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/OBV.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=82}\cr \url{https://www.linnsoft.com/techind/balance-open-interest}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:on_balance_volume_obv}\cr } \seealso{ See \code{\link{chaikinAD}}. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/RSI.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/RSI.R \name{RSI} \alias{RSI} \title{Relative Strength Index} \usage{ RSI(price, n = 14, maType, ...) } \arguments{ \item{price}{Price series that is coercible to xts or matrix.} \item{n}{Number of periods for moving averages.} \item{maType}{Either: \enumerate{ \item A function or a string naming the function to be called. \item A \emph{list} with the first component like (1) above, and additional parameters specified as \emph{named} components. See Examples. }} \item{\dots}{Other arguments to be passed to the \code{maType} function in case (1) above.} } \value{ A object of the same class as \code{price} or a vector (if \code{try.xts} fails) containing the RSI values. } \description{ The Relative Strength Index (RSI) calculates a ratio of the recent upward price movements to the absolute price movement. Developed by J. Welles Wilder. } \details{ The RSI calculation is \code{RSI = 100 - 100 / ( 1 + RS )}, where \code{RS} is the smoothed ratio of 'average' gains over 'average' losses. The 'averages' aren't true averages, since they're divided by the value of \code{n} and not the number of periods in which there are gains/losses. } \note{ The RSI is usually interpreted as an overbought/oversold (over 70 / below 30) indicator. Divergence with price may also be useful. For example, if price is making new highs/lows, but RSI is not, it could indicate a reversal. You can calculate a stochastic RSI by using the function \code{\link{stoch}} on RSI values. } \examples{ data(ttrc) price <- ttrc[,"Close"] # Default case rsi <- RSI(price) # Case of one 'maType' for both MAs rsiMA1 <- RSI(price, n=14, maType="WMA", wts=ttrc[,"Volume"]) # Case of two different 'maType's for both MAs rsiMA2 <- RSI(price, n=14, maType=list(maUp=list(EMA),maDown=list(WMA))) } \references{ The following site(s) were used to code/document this indicator: \cr Relative Strength Index:\cr \url{https://www.fmlabs.com/reference/RSI.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=100}\cr \url{https://www.linnsoft.com/techind/relative-strength-index-rsi}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:relative_strength_index_rsi}\cr \cr Stochastic RSI:\cr \url{https://www.fmlabs.com/reference/StochRSI.htm}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:stochrsi}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. See \code{\link{CMO}} for a variation on RSI. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/SAR.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/SAR.R \name{SAR} \alias{SAR} \title{Parabolic Stop-and-Reverse} \usage{ SAR(HL, accel = c(0.02, 0.2)) } \arguments{ \item{HL}{Object that is coercible to xts or matrix and contains High-Low prices.} \item{accel}{accel[1]: Acceleration factor.\cr accel[2]: Maximum acceleration factor.} } \value{ A object of the same class as \code{HL} or a vector (if \code{try.xts} fails) containing the Parabolic Stop and Reverse values. } \description{ The Parabolic Stop-and-Reverse calculates a trailing stop. Developed by J. Welles Wilder. } \details{ The calculation for the SAR is quite complex. See the URLs in the references section for calculation notes. The SAR assumes that you are always in the market, and calculates the Stop And Reverse point when you would close a long position and open a short position or vice versa. } \examples{ data(ttrc) sar <- SAR(ttrc[,c("High","Low")]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.linnsoft.com/techind/parabolic-sar-sar}\cr \url{https://www.fmlabs.com/reference/SAR.htm}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:parabolic_sar}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=87} } \seealso{ See \code{\link{ATR}} and \code{\link{ADX}}, which were also developed by Welles Wilder. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/SNR.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/SNR.R \name{SNR} \alias{SNR} \title{Signal to Noise Ratio} \usage{ SNR(HLC, n, ...) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices.} \item{n}{Number of periods for moving average.} \item{...}{Other arguments to be passed to \code{\link{ATR}}.} } \value{ A object of the same class as HLC or a matrix (if try.xts fails) containing the signal to noise ratio. } \description{ The n-day SNR for a given market is calculated by taking the absolute price change over an n-day period and dividing it by the average n-day volatility. } \details{ \deqn{SNR_n = \frac{|C_t - C_{t-n}|}{ATR_n} }{SNR = abs(Cl - lag(Cl,n)) / ATR(HLC, n)$atr} Using average true range as the volatility measure captures more of the intraday and overnight volatility in a way that a measurement of Close-to-Close price change does not. The interpretation is then relatively intuitive: an SNR value of five indicates that the market has moved five times the volatility (average true range) over the given look-back period. } \references{ Skeggs, James and Hill, Alex (2015). Back in Black Part 2: The Opportunity Set for Trend Following. } \author{ Peter Carl } ================================================ FILE: man/TDI.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/TDI.R \name{TDI} \alias{TDI} \title{Trend Detection Index} \usage{ TDI(price, n = 20, multiple = 2) } \arguments{ \item{price}{Price series that is coercible to xts or matrix.} \item{n}{Number of periods to use.} \item{multiple}{Multiple used to calculate (2).} } \value{ A object of the same class as \code{price} or a matrix (if \code{try.xts} fails) containing the columns: \describe{ \item{ tdi }{ The Trend Detection Index. } \item{ di }{ The Direction Indicator. } } } \description{ The Trend Detection Index (TDI) attempts to identify starting and ending trends. Developed by M. H. Pee. } \details{ The TDI is the (1) absolute value of the \code{n}-day sum of the \code{n}-day momentum, minus the quantity of (2) \code{multiple}*\code{n}-day sum of the absolute value of the \code{n}-day momentum, minus (3) \code{n}-day sum of the absolute value of the \code{n}-day momentum. I.e. TDI = (1) - [ (2) - (3) ] The direction indicator is the sum of the \code{n}-day momentum over the last \code{n} days. See URL in references section for further details. } \note{ Positive/negative TDI values signal a trend/consolidation. A positive/ negative direction indicator signals a up/down trend. I.e. buy if the TDI and the direction indicator are positive, and sell if the TDI is positive while the direction indicator is negative. } \examples{ data(ttrc) tdi <- TDI(ttrc[,"Close"], n=30) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.linnsoft.com/techind/trend-detection-index-tdi}\cr } \seealso{ See \code{\link{aroon}}, \code{\link{CCI}}, \code{\link{ADX}}, \code{\link{VHF}}, \code{\link{GMMA}} for other indicators that measure trend direction/strength. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/TRIX.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/TRIX.R \name{TRIX} \alias{TRIX} \title{Triple Smoothed Exponential Oscillator} \usage{ TRIX(price, n = 20, nSig = 9, maType, percent = TRUE, ...) } \arguments{ \item{price}{Price series that is coercible to xts or matrix.} \item{n}{Number of periods for moving average.} \item{nSig}{Number of periods for signal line moving average.} \item{maType}{Either: \enumerate{ \item A function or a string naming the function to be called. \item A \emph{list} with the first component like (1) above, and additional parameters specified as \emph{named} components. See Examples. }} \item{percent}{logical; if \code{TRUE}, the rate of change is calculated using the \code{ROC} function, otherwise the \code{momentum} function is used.} \item{\dots}{Other arguments to be passed to the \code{maType} function in case (1) above.} } \value{ A object of the same class as \code{price} or a vector (if \code{try.xts} fails) containing the TRIX values. } \description{ The TRIX indicator calculates the rate of change of a triple exponential moving average. Developed by Jack K. Hutson. } \details{ The TRIX is calculated as follows:\cr 3MA = \code{MA}( \code{MA}( \code{MA}(\code{price}) ) )\cr trix = 100 * [ 3MA(t) / 3MA(t-1) - 1 ] } \note{ Buy/sell signals are generated when the TRIX crosses above/below zero. A nine-period EMA of the TRIX is used as a default signal line. Buy/sell signals are generated when the TRIX crosses above/below the signal line and is also above/below zero. } \examples{ data(ttrc) trix <- TRIX(ttrc[,"Close"]) trix4 <- TRIX(ttrc[,"Close"], maType=list(list(SMA), list(EMA, wilder=TRUE), list(SMA), list(DEMA))) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/default.htm?url=TRIX.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=114}\cr \url{https://www.linnsoft.com/techind/trix-triple-smoothed-exponential-oscillator}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:trix}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/TTR.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/TTR-package.R \docType{package} \name{TTR} \alias{TTR} \alias{TTR-package} \title{Functions to create Technical Trading Rules (TTR)} \description{ This package contains many of the most popular technical analysis functions, as well as functions to retrieve U.S. stock symbols, and data from Yahoo Finance. } \details{ Users will probably be most interested in the following functions:\cr \code{\link{ADX}}\cr \code{\link{BBands}}\cr \code{\link{changes}}\cr \code{\link{MovingAverages}}\cr \code{\link{MACD}}\cr \code{\link{RSI}}\cr \code{\link{runFun}}\cr \code{\link{stoch}}\cr \code{\link{VWAP}}\cr \code{\link{WebData}}\cr } \examples{ data(ttrc) # Bollinger Bands bbands <- BBands( ttrc[,c("High","Low","Close")] ) # Directional Movement Index adx <- ADX(ttrc[,c("High","Low","Close")]) # Moving Averages ema <- EMA(ttrc[,"Close"], n=20) sma <- SMA(ttrc[,"Close"], n=20) # MACD macd <- MACD( ttrc[,"Close"] ) # RSI rsi <- RSI(ttrc[,"Close"]) # Stochastics stochOsc <- stoch(ttrc[,c("High","Low","Close")]) ### Note: you must have a working internet connection ### for the examples below to work! if (interactive()) { # Fetch U.S. symbols from the internet nyseSymbols <- stockSymbols("NYSE") # Fetch Yahoo! Finance data from the internet ge <- getYahooData("GE", 19990404, 20050607, adjust = FALSE) } } \references{ The following sites were used to code/document this package:\cr \url{https://www.fmlabs.com/reference/default.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/}\cr \url{https://www.linnsoft.com/indicators}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators}\cr } \seealso{ Useful links: \itemize{ \item \url{https://github.com/joshuaulrich/TTR} \item Report bugs at \url{https://github.com/joshuaulrich/TTR/issues} } } \author{ Joshua Ulrich Maintainer: Joshua Ulrich } \keyword{package} ================================================ FILE: man/TTRtools.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/TTRtools.R \name{lags} \alias{lags} \alias{growth} \alias{naCheck} \title{Miscellaneous Tools} \usage{ lags(x, n = 1) growth(price, signals, ...) naCheck(x, n = 0) } \arguments{ \item{x}{Object that is coercible to xts or matrix.} \item{n}{Number of periods to use.} \item{price}{Price series that is coercible to xts or matrix.} \item{signals}{Signals to use (defaults to vector of ones). Use '0' for no position, '1' for long position, and '-1' for short position.} \item{\dots}{Further arguments to be passed from or to other methods.} } \value{ \code{growth} returns a vector of the growth of the investment. \code{lags} returns a matrix of lagged values of the original vector. } \description{ Various functions that may be useful in designing technical trading rules. } \details{ \code{growth} calculates the growth of an investment using given prices and signals. \code{lags} calculates the lags of a given series. } \note{ In \code{growth} you can specify the number of periods and type of compounding to use when calculating returns of the price series via the \code{'\dots'} argument. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/VHF.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/VHF.R \name{VHF} \alias{VHF} \title{Vertical Horizontal Filter} \usage{ VHF(price, n = 28) } \arguments{ \item{price}{Object that is coercible to xts or matrix and contains a Close price series, or a High-Low-Close price series.} \item{n}{Number of periods to use.} } \value{ A object of the same class as \code{price} or a vector (if \code{try.xts} fails) containing the VHF values. } \description{ The Vertical Horizontal Filter (VHF) attempts to identify starting and ending trends. Developed by Adam White. } \details{ The VHF is calculated by subtracting the \code{n}-period lowest low from the \code{n}-period highest high and dividing that result by the \code{n}-period rolling sum of the close price changes. } \note{ If Close prices are given, the function calculates the max/min using only those prices (the default). If HLC prices are given, the function calculates the max/min using the high/low prices (added for flexibility). } \examples{ data(ttrc) vhf.close <- VHF(ttrc[,"Close"]) vhf.hilow <- VHF(ttrc[,c("High","Low","Close")]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=119}\cr } \seealso{ See \code{\link{aroon}}, \code{\link{CCI}}, \code{\link{ADX}}, \code{\link{TDI}}, \code{\link{GMMA}} for other indicators that measure trend direction/strength. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/WPR.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/WPR.R \name{WPR} \alias{WPR} \title{William's \%R} \usage{ WPR(HLC, n = 14, scale = FALSE) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices. If only a univariate series is given, it will be used. See details.} \item{n}{Number of periods to use.} \item{scale}{Scale the result to be between 0 and -100.} } \value{ A object of the same class as \code{HLC} or a vector (if \code{try.xts} fails) containing the William's \%R values. } \description{ William's \% R. } \details{ If an High-Low-Close series is provided, the indicator is calculated using the high/low values. If a vector is provided, the calculation only uses that series. } \note{ The William's \%R calculation is similar to stochastics' fast \%K, and the result of \code{WPR} is equal to \code{1-fastK}. The value for William's \%R will be 0.5 whenever the highest high and lowest low are the same over the last \code{n} periods. William's \%R is usually scaled to be between 0 and -100, which is not what \code{WPR} returns by default. Set \code{scale = TRUE} to return the result with the usual scaling. } \examples{ data(ttrc) hlc <- ttrc[,c("High","Low","Close")] stochOsc <- stoch(hlc) stochWPR <- WPR(hlc) # WPR is a transformation of stochastics' fastK all.equal(stochWPR, 1-stochOsc[,'fastK']) # TRUE # WPR converted to the usual scaling between 0 and -100 scaledWPR <- WPR(hlc, scale=TRUE) plot(tail(stochOsc[,"fastK"], 100), type="l", main="Fast \%K and Williams \%R", ylab="", ylim=range(cbind(stochOsc, stochWPR), na.rm=TRUE) ) lines(tail(stochWPR, 100), col="blue") lines(tail(1-stochWPR, 100), col="red", lty="dashed") } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/WilliamsR.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=126}\cr \url{https://www.linnsoft.com/techind/williams-r-wpr}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:williams_r}\cr } \seealso{ See \code{\link{stoch}}. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/WebData.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/WebData.R \name{stockSymbols} \alias{stockSymbols} \alias{WebData} \alias{getYahooData} \title{Fetch Internet Data} \usage{ stockSymbols( exchange = c("AMEX", "NASDAQ", "NYSE", "ARCA", "BATS", "IEX"), sort.by = c("Exchange", "Symbol"), quiet = FALSE ) getYahooData( symbol, start, end, freq = "daily", type = "price", adjust = TRUE, quiet = FALSE ) } \arguments{ \item{exchange}{Character vector of exchange names on which desired instrument symbols are traded.} \item{sort.by}{Character vector of columns by which returned data will be sorted. Must be one or more of \code{"Name"}, \code{"Symbol"}, \code{"Market.Cap"}, or \code{"Exchange"}.} \item{quiet}{Logical; if \code{TRUE}, status messages will be printed to the console.} \item{symbol}{Yahoo! Finance instrument symbol.} \item{start}{Numeric; first date of desired data, in YYYYMMDD format. Default is first date of series.} \item{end}{Numeric; last date of desired data, in YYYYMMDD format. Default is last date of series.} \item{freq}{Desired data frequency. One of \code{"daily"}, \code{"weekly"}, \code{"monthly"}.} \item{type}{Type of data to return. One of \code{"price"}, or \code{"split"}. \code{type="split"} will return both split and dividend data.} \item{adjust}{Logical; if \code{TRUE}, the Open, High, Low, and Close prices will be adjusted for dividends and splits, and Volume will be adjusted for dividends.} } \value{ \code{getYahooData} returns an xts object containing the columns: \code{stockSymbols} returns a character vector containing all the listed symbols for the given exchanges. \describe{ \item{ Date }{ Trade date, in CCYYMMDD format. } \item{ Open }{ Open price. } \item{ High }{ High price. } \item{ Low }{ Low price. } \item{ Close }{ Close price. } \item{ Volume }{ Volume. } } } \description{ Get investment data from the internet. } \details{ \code{getYahooData} fetches individual stock data from the Yahoo! Finance website. It also adjusts price for splits and dividends, and volume for splits. See the Warning section, and note that it is deprecated in favor of getSymbols in the quantmod package. \code{stockSymbols} fetches instrument symbols from the nasdaq.com website, and adjusts the symbols to be compatible with the Yahoo! Finance website. } \note{ The symbols returned by \code{stockSymbols} may not be in the format necessary to retrieve data using \code{getYahooData}. \code{getYahooData} has only been tested on daily data. It isn't known if the function correctly adjusts data for any other frequency. } \section{Warning}{ As of TTR 0.23-2, \code{getYahooData} has been patched to work with changes to Yahoo Finance, which also included the following changes to the raw data: \itemize{ \item The adjusted close column appears to no longer include dividend adjustments \item The open, high, and low columns are adjusted for splits, and \item The raw data may contain missing values. \item The raw data may contain errors. } As of TTR 0.24.2, \code{stockSymbols} began using data from NASDAQ's FTP site because the data from the original site is no longer available. This new file does not contain data for the columns: LastSale, MarketCap, IPOyear, Sector, and Industry. All the columns still appear in the results,#' but all the values in the columns are set to \code{NA}. } \examples{ ### Note: you must have a working internet ### connection for these examples to work! if (interactive()) { ge <- getYahooData("GE", 19990404, 20050607, adjust = FALSE) nyse.symbols <- stockSymbols("NYSE") } } \references{ \itemize{ \item \href{https://quant.stackexchange.com/questions/1640/where-to-download-list-of-all-common-stocks-traded-on-nyse-nasdaq-and-amex/1862}{Quant StackExchange: Download list of all stock symbols?} \item \href{https://www.nasdaqtrader.com/trader.aspx?id=CQSsymbolconvention}{CQS symbol convention} \item \href{https://web.archive.org/web/20111023221931/http://help.yahoo.com/l/us/yahoo/finance/quotes/quote-02.html}{Yahoo Finance symbol conventions} } } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/ZigZag.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/ZigZag.R \name{ZigZag} \alias{ZigZag} \alias{zigzag} \title{Zig Zag} \usage{ ZigZag(HL, change = 10, percent = TRUE, retrace = FALSE, lastExtreme = TRUE) } \arguments{ \item{HL}{Object that is coercible to xts or matrix and contains either a High-Low price series, or a Close price series.} \item{change}{Minimum price movement, either in dollars or percent (see \code{percent}).} \item{percent}{Use percentage or dollar change?} \item{retrace}{Is \code{change} a retracement of the previous move, or an absolute change from peak to trough?} \item{lastExtreme}{If the extreme price is the same over multiple periods, should the extreme price be the first or last observation?} } \value{ A object of the same class as \code{HL} or a vector (if \code{try.xts} fails) containing the Zig Zag indicator. } \description{ Zig Zag higlights trends by removing price changes smaller than \code{change} and interpolating lines between the extreme points. } \details{ The Zig Zag is non-predictive. The purpose of the Zig Zag is filter noise and make chart patterns clearer. It's more a visual tool than an indicator. } \note{ If High-Low prices are given, the function calculates the max/min using the high/low prices. Otherwise the function calculates the max/min of the single series. } \section{Warning}{ The last value of the ZigZag indicator is unstable (i.e. unknown) until the turning point actually occurs. Therefore this indicator isn't well-suited for use for systematic trading strategies. } \examples{ ## Get Data and Indicator ## data(ttrc) zz <- ZigZag( ttrc[,c("High", "Low")], change=20 ) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/default.htm?url=ZigZag.htm}\cr \url{https://www.linnsoft.com/techind/zig-zag-indicator-zig-zzo}\cr \url{https://www.linnsoft.com/techind/zig-zag-oscillator-indicator-zzo}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=127}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:zigzag}\cr } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/adjRatios.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/adjRatios.R \name{adjRatios} \alias{adjRatios} \alias{adjust} \title{Split and dividend adjustment ratios} \usage{ adjRatios(splits, dividends, close) } \arguments{ \item{splits}{Split series that is coercible to xts.} \item{dividends}{Dividend series that is coercible to xts.} \item{close}{Close price series that is coercible to xts.} } \value{ A xts object containing the columns: \describe{ \item{ Split }{ The split adjustment ratio. } \item{ Div }{ The dividend adjustment ratio. } } } \description{ Create split and dividend adjustment ratio vectors. } \details{ \itemize{ \item If only \code{splits} is provided, the resulting object will only have as many observations as \code{splits}. \item If \code{splits} and \code{close} are provided, the resulting object will have as many observations as \code{max(NROW(splits), NROW(close))}. \item \code{close} is required if \code{dividends} is provided. } } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/aroon.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/aroon.R \name{aroon} \alias{aroon} \title{Aroon} \usage{ aroon(HL, n = 20) } \arguments{ \item{HL}{Object that is coercible to xts or matrix and contains either a High-Low price series, or a Close price series.} \item{n}{Number of periods to use in the calculation.} } \value{ A object of the same class as \code{HL} or a matrix (if \code{try.xts} fails) containing the columns: \describe{ \item{ aroonUp }{ The Aroon up indicator. } \item{ aroonDn }{ The Aroon down indicator. } \item{ oscillator }{ The Aroon oscillator (\code{aroonUp - aroonDn}). } } } \description{ The Aroon indicator attempts to identify starting trends. The indicator consists of up and down lines, which measure how long it has been since the highest high/lowest low has occurred in the last \code{n} periods. Developed by Tushar Chande in 1995. } \details{ Aroon up (down) is the elapsed time, expressed as a percentage, between today and the highest (lowest) price in the last \code{n} periods. If today's price is a new high (low) Aroon up (down) will be 100. Each subsequent period without another new high (low) causes Aroon up (down) to decrease by (1 / \code{n}) x 100. } \note{ If High-Low prices are given, the function calculates the max/min using the high/low prices. Otherwise the function calculates the max/min of the single series. Up (down) trends are indicated when the aroonUp(Dn) is between 70 and 100. Strong trends are indicated when when the aroonUp(Dn) is above 70 while the aroonDn(Up) is below 30. Also, crossovers may be useful. } \examples{ ## Get Data and Indicator ## data(ttrc) trend <- aroon( ttrc[,c("High", "Low")], n=20 ) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/Aroon.htm}\cr \url{https://www.fmlabs.com/reference/AroonOscillator.htm}\cr \url{https://www.linnsoft.com/techind/aroon-arn}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:aroon}\cr } \seealso{ See \code{\link{CCI}}, \code{\link{ADX}}, \code{\link{TDI}}, \code{\link{VHF}}, \code{\link{GMMA}} for other indicators that measure trend direction/strength. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/bollingerBands.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/bollingerBands.R \name{BBands} \alias{BBands} \alias{bollingerBands} \title{Bollinger Bands} \usage{ BBands(HLC, n = 20, maType, sd = 2, ...) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices. If only a univariate series is given, it will be used. See details.} \item{n}{Number of periods for moving average.} \item{maType}{A function or a string naming the function to be called.} \item{sd}{The number of standard deviations to use.} \item{\dots}{Other arguments to be passed to the \code{maType} function.} } \value{ A object of the same class as \code{HLC} or a matrix (if \code{try.xts} fails) containing the columns: \describe{ \item{ dn }{ The lower Bollinger Band. } \item{ mavg }{ The middle Moving Average (see notes). } \item{ up }{ The upper Bollinger Band. } \item{ pctB }{ The \%B calculation. } } } \description{ Bollinger Bands are a way to compare a security's volatility and price levels over a period of time. Developed by John Bollinger. } \details{ Bollinger Bands consist of three lines: The middle band is generally a 20-period SMA of the typical price ([high + low + close]/3). The upper and lower bands are \code{sd} standard deviations (generally 2) above and below the MA. The middle band is usually calculated using the typical price, but if a univariate series (e.g. Close, Weighted Close, Median Price, etc.) is provided, it will be used instead. } \note{ Using any moving average other than SMA will result in inconsistencies between the moving average calculation and the standard deviation calculation. Since, by definition, a rolling standard deviation uses a simple moving average. } \examples{ ## The examples below show the differences between using a ## High-Low-Close series, and just a close series when ## calculating Bollinger Bands. data(ttrc) bbands.HLC <- BBands( ttrc[,c("High","Low","Close")] ) bbands.close <- BBands( ttrc[,"Close"] ) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/Bollinger.htm}\cr \url{https://www.fmlabs.com/reference/BollingerWidth.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=36}\cr \url{https://www.linnsoft.com/techind/bollinger-bands}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_band_width}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/chaikinAD.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/chaikinAD.R \name{chaikinAD} \alias{chaikinAD} \title{Chaikin Accumulation / Distribution} \usage{ chaikinAD(HLC, volume) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices.} \item{volume}{Vector or matrix of volume observations corresponding to the \code{HLC} object.} } \value{ A object of the same class as \code{HLC} and \code{volume} or a vector (if \code{try.xts} fails) containing the accumulation / distribution values. } \description{ The Chaikin Accumulation / Distribution (AD) line is a measure of the money flowing into or out of a security. It is similar to On Balance Volume (OBV). Developed by Marc Chaikin. } \details{ The AD line is similar to OBV; the difference is that OBV sums volume multiplied by +/- 1 if the close is higher/lower than the previous close, while the AD line multiplies volume by the close location value (CLV). } \note{ The Accumulation/Distribution Line is interpreted by looking for a divergence in the direction of the indicator relative to price. } \examples{ data(ttrc) ad <- chaikinAD(ttrc[,c("High","Low","Close")], ttrc[,"Volume"]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/AccumDist.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=27}\cr \url{https://www.linnsoft.com/techind/accumulation-distribution}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line}\cr } \seealso{ See \code{\link{OBV}}, and \code{\link{CLV}}. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/chaikinVolatility.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/chaikinVolatility.R \name{chaikinVolatility} \alias{chaikinVolatility} \title{Chaikin Volatility} \usage{ chaikinVolatility(HL, n = 10, maType, ...) } \arguments{ \item{HL}{Object that is coercible to xts or matrix and contains High-Low prices.} \item{n}{Number of periods for moving average.} \item{maType}{A function or a string naming the function to be called.} \item{\dots}{Other arguments to be passed to the \code{maType} function.} } \value{ A object of the same class as \code{HL} or a vector (if \code{try.xts} fails) containing the Chaikin Volatility values. } \description{ Chaikin Volatility measures the rate of change of the security's trading range. Developed by Marc Chaikin. } \details{ The Chaikin Volatility indicator defines volatility as an increase in the difference between the high and low. } \note{ A rapid increase in Chaikin Volatility indicates an approaching bottom. A slow decrease in Chaikin Volatility indicates an approaching top. } \examples{ data(ttrc) volatility <- chaikinVolatility(ttrc[,c("High","Low")]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/ChaikinVolatility.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=120}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. See \code{\link{TR}} for another volatility measure. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/changes.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/changes.R \name{ROC} \alias{ROC} \alias{changes} \alias{momentum} \title{Rate of Change / Momentum} \usage{ ROC(x, n = 1, type = c("continuous", "discrete"), na.pad = TRUE) momentum(x, n = 1, na.pad = TRUE) } \arguments{ \item{x}{Price, volume, etc. series that is coercible to xts or matrix.} \item{n}{Number of periods to use.} \item{type}{Compounding type; either \code{"continuous"} (the default) or \code{"discrete"}.} \item{na.pad}{Should periods prior to \code{n} be appended? Default is \code{TRUE}.} } \value{ A object of the same class as \code{x} or a vector (if \code{try.xts} fails) containing the rate-of-change (or return) values for \code{ROC} or a vector containing the differenced price series for \code{momentum}. } \description{ Calculate the (rate of) change of a series over \code{n} periods. } \details{ The ROC indicator provides the percentage difference of a series over two observations, while the momentum indicator simply provides the difference. } \examples{ data(ttrc) roc <- ROC(ttrc[,"Close"]) mom <- momentum(ttrc[,"Close"]) } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/keltnerChannels.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/keltnerChannels.R \name{keltnerChannels} \alias{keltnerChannels} \title{Keltner Channels} \usage{ keltnerChannels(HLC, n = 20, maType, atr = 2, ...) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices. If only a univariate series is given, it will be used. See details.} \item{n}{Number of periods for moving average.} \item{maType}{A function or a string naming the function to be called.} \item{atr}{The number of average true range distances to apply.} \item{...}{Other arguments to be passed to the maType function.} } \value{ A object of the same class as \code{HLC} or a matrix (if \code{try.xts} fails) containing the columns: \describe{ \item{SMA}{ Simple moving average. } \item{EMA}{ Exponential moving average. } } \item{dn}{ The lower Keltner Channel. } \item{mavg}{ The middle moving average. } \item{up}{ The upper Keltner Channel. } } \description{ Keltner Channels are volatility-based envelopes set above and below a moving average. This indicator is similar to Bollinger Bands, but Keltner Channels use the Average True Range (ATR) to set channel distance. } \details{ Keltner Channels are a trend following indicator, and can also be used to identify overbought and oversold levels when there is no trend. Chester Keltner is credited with the original version of Keltner Channels in his 1960 book. Linda Bradford Raschke introduced the newer version of Keltner Channels in the 1980s. } \section{Details }{ Keltner Channels consist of three lines: The middle band is generally a 20-period EMA of the typical price ([high + low + close]/3). The upper and lower bands are multiples of average true range (usually 2) above and below the MA. The middle band is usually calculated using the typical price, but if a univariate series (e.g. Close, Weighted Close, Median Price, etc.) is provided, it will be used instead. } \examples{ data(ttrc) kc <- keltnerChannels(ttrc[,c("High","Low","Close")]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels}\cr \url{https://www.linnsoft.com/techind/keltner-channels-keltu-keltd}\cr \url{https://www.investopedia.com/terms/k/keltnerchannel.asp}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. } \author{ Nick Procyk, Joshua Ulrich References } \keyword{ts} ================================================ FILE: man/priceBands.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/priceBands.R \name{PBands} \alias{PBands} \alias{priceBands} \title{Construct (optionally further smoothed and centered ) volatility bands around prices} \usage{ PBands( prices, n = 20, maType = "SMA", sd = 2, ..., fastn = 2, centered = FALSE, lavg = FALSE ) } \arguments{ \item{prices}{A univariate series of prices.} \item{n}{Number of periods to average over.} \item{maType}{A function or a string naming the function to be called.} \item{sd}{The number of standard deviations to use.} \item{\dots}{any other pass-thru parameters, usually for function named by \code{maType}.} \item{fastn}{Number of periods to use for smoothing higher-frequency 'noise'.} \item{centered}{Whether to center the bands around a series adjusted for high frequency noise, default \code{FALSE}.} \item{lavg}{Whether to use a longer \code{(n*2)} smoothing period for centering, default \code{FALSE}.} } \value{ A object of the same class as \code{prices} or a matrix (if \code{try.xts} fails) containing the columns: \describe{ \item{ dn }{ The lower price volatility Band. } \item{ center }{ The smoothed centerline (see details). } \item{ up }{ The upper price volatility Band. } } } \description{ John Bollinger's famous adaptive volatility bands most often use the typical price of an HLC series, or may be calculated on a univariate price series (see \code{\link{BBands}}). } \details{ This function applies a second moving average denoted by \code{fastn} to filter out higher-frequency noise, making the bands somewhat more stable to temporary fluctuations and spikes. If \code{centered} is \code{TRUE}, the function also further smoothes and centers the bands around a centerline adjusted to remove this higher frequency noise. If \code{lavg} is also \code{TRUE}, the smoothing applied for the middle band (but not the volatility bands) is doubled to further smooth the price-response function. If you have multiple different price series in \code{prices}, and want to use this function, call this functions using \code{lapply(prices,PBands,...)}. } \examples{ data(ttrc) pbands.close <- PBands( ttrc[,"Close"] ) } \seealso{ \code{\link{BBands}} } \author{ Brian G. Peterson } \keyword{ts} ================================================ FILE: man/rollFun.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/rollFun.R \name{rollSFM} \alias{rollSFM} \alias{rollFun} \title{Analysis of Running/Rolling/Moving Windows} \usage{ rollSFM(Ra, Rb, n = 60) } \arguments{ \item{Ra}{Object coercible to xts or matrix, containing the excess return for an individual security} \item{Rb}{Object coercible to xts or matrix, containing the market / benchmark return} \item{n}{Number of periods to use in the window} } \value{ A object of the same class as \code{Ra} (and \code{Rb}?) or a vector (if \code{try.xts} fails). \describe{ \item{rollSFM}{returns single-factor model parameters and R-squared over a n-period moving window.} } } \description{ Various functions to analyze data over a moving window of periods. } \references{ The following site(s) were used to code/document this indicator: \url{https://en.wikipedia.org/wiki/Simple_linear_regression}\cr } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/runFun.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/runFun.R \name{runSum} \alias{runSum} \alias{runFun} \alias{runMin} \alias{runMax} \alias{runRange} \alias{runMean} \alias{runMedian} \alias{runCov} \alias{runCor} \alias{runVar} \alias{runSD} \alias{runMAD} \alias{wilderSum} \title{Analysis of Running/Rolling/Moving Windows} \usage{ runSum(x, n = 10, cumulative = FALSE) runMin(x, n = 10, cumulative = FALSE) runMax(x, n = 10, cumulative = FALSE) runRange(x, n = 10, cumulative = FALSE) runMean(x, n = 10, cumulative = FALSE) runMedian(x, n = 10, non.unique = "mean", cumulative = FALSE) runCov(x, y, n = 10, use = "all.obs", sample = TRUE, cumulative = FALSE) runCor(x, y, n = 10, use = "all.obs", sample = TRUE, cumulative = FALSE) runVar(x, y = NULL, n = 10, sample = TRUE, cumulative = FALSE) runSD(x, n = 10, sample = TRUE, cumulative = FALSE) runMAD( x, n = 10, center = NULL, stat = "median", constant = 1.4826, non.unique = "mean", cumulative = FALSE ) wilderSum(x, n = 10) } \arguments{ \item{x}{Object coercible to xts or matrix.} \item{n}{Number of periods to use in the window or, if \code{cumulative=TRUE}, the number of observations to use before the first result is returned. Must be between 1 and \code{nrow(x)}, inclusive.} \item{cumulative}{Logical, use from-inception calculation?} \item{non.unique}{One of 'mean', 'max', or 'min'; which compute their respective statistics for the two middle values of even-sized samples.} \item{y}{Object coercible to xts or matrix.} \item{use}{Only \code{"all.obs"} currently implemented.} \item{sample}{Logical, sample covariance if \code{TRUE} (denominator of \code{n-1})} \item{center}{The values to use as the measure of central tendency, around which to calculate deviations. The default (\code{NULL}) uses the median.} \item{stat}{Statistic to calculate, one of 'median' or 'mean' (e.g. median absolute deviation or mean absolute deviation, respectively.)} \item{constant}{Scale factor applied to approximate the standard deviation.} } \value{ A object of the same class as \code{x} and \code{y} or a vector (if \code{try.xts} fails). \describe{ \item{runSum}{returns sums over a n-period moving window.} \item{runMin}{returns minimums over a n-period moving window.} \item{runMax}{returns maximums over a n-period moving window.} \item{runRange}{returns a maxtrix with min and max values for x over a n-period moving window.} \item{runMean}{returns means over a n-period moving window.} \item{runMedian}{returns medians over a n-period moving window.} \item{runCov}{returns covariances over a n-period moving window.} \item{runCor}{returns correlations over a n-period moving window.} \item{runVar}{returns variances over a n-period moving window.} \item{runSD}{returns standard deviations over a n-period moving window.} \item{runMAD}{returns median/mean absolute deviations over a n-period moving window.} \item{wilderSum}{retuns a Welles Wilder style weighted sum over a n-period moving window.} } } \description{ Various functions to analyze data over a moving window of periods. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/runPercentRank.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/percentRank.R \name{runPercentRank} \alias{runPercentRank} \alias{percentRank} \alias{PercentRank} \title{Percent Rank over a Moving Window} \usage{ runPercentRank(x, n = 260, cumulative = FALSE, exact.multiplier = 0.5) } \arguments{ \item{x}{Object coercible to xts or matrix.} \item{n}{Number of periods to use in the window or, if \code{cumulative=TRUE}, the number of observations to use before the first result is returned. Must be between 1 and \code{nrow(x)}, inclusive.} \item{cumulative}{Logical, use from-inception calculation?} \item{exact.multiplier}{The weight applied to identical values in the window. Must be between 0 and 1, inclusive. See details.} } \value{ A object of percent ranks over a n-period moving window of the same class as \code{x} and \code{y} or a vector (if \code{try.xts} fails). } \description{ This function computes a running/rolling percentage rank. } \details{ The computation for a percentage rank can vary depending on the weight given to values in the window that are equal to the value being ranked. This weight can be set using the \code{exact.multiplier} argument which defaults to 0.5. \code{exact.multiplier = 0} scores equal values in the lookback window as always being greater than the value being ranked. \code{exact.multiplier = 1} scores equal values as being below the value being ranked. Any multiplier between 0 and 1 counts that proportion of the equal values as being below the value being ranked. The value of \code{exact.multiplier} has the most impact when the window is relatively small or when the number of discrete values in the window is small. For non-repeating values, changing \code{exact.multiplier = 0} to \code{exact.multiplier = 1} for a window of size \code{N} will shift the resulting percentile rankings by \code{1/N}. It is equivalent to changing the question from, "how many values are < the value" to "how many values are <= the value". } \note{ This computation is different from the one used in Microsoft Excel's \code{PERCENTRANK} formula. Excel's computation is rather strange and gives inconsistent results as it uses interpolation to rank values that are not found within the lookback window. } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://en.wikipedia.org/wiki/Percentile_rank}\cr } \author{ Charlie Friedemann } \keyword{ts} ================================================ FILE: man/stochastics.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/stochastics.R \name{stoch} \alias{stoch} \alias{stochastics} \alias{stochastic} \alias{SMI} \alias{\%K} \alias{\%D} \title{Stochastic Oscillator / Stochastic Momentum Index} \usage{ stoch( HLC, nFastK = 14, nFastD = 3, nSlowD = 3, maType, bounded = TRUE, smooth = 1, ... ) SMI(HLC, n = 13, nFast = 2, nSlow = 25, nSig = 9, maType, bounded = TRUE, ...) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices. If only a univariate series is given, it will be used. See details.} \item{nFastK}{Number of periods for fast \%K (i.e. the number of past periods to use).} \item{nFastD}{Number of periods for fast \%D (i.e. the number smoothing periods to apply to fast \%K).} \item{nSlowD}{Number of periods for slow \%D (i.e. the number smoothing periods to apply to fast \%D).} \item{maType}{Either: \enumerate{ \item A function or a string naming the function to be called. \item A \emph{list} with the first component like (1) above, and additional parameters specified as \emph{named} components. See Examples. }} \item{bounded}{Logical, should current period's values be used in the calculation?} \item{smooth}{Number of internal smoothing periods to be applied before calculating FastK. See Details.} \item{\dots}{Other arguments to be passed to the \code{maType} function in case (1) above.} \item{n}{Number of periods to use.} \item{nFast}{Number of periods for initial smoothing.} \item{nSlow}{Number of periods for double smoothing.} \item{nSig}{Number of periods for signal line.} } \value{ A object of the same class as \code{HLC} or a matrix (if \code{try.xts} fails) containing the columns: \describe{ \item{ fastK }{ Stochastic Fast \%K } \item{ fastD }{ Stochastic Fast \%D } \item{ slowD }{ Stochastic Slow \%D } \item{ SMI }{ Stochastic Momentum Index } \item{ signal }{ Stochastic Momentum Index signal line } } } \description{ The stochastic oscillator is a momentum indicator that relates the location of each day's close relative to the high/low range over the past \code{n} periods. Developed by George C. Lane in the late 1950s. The SMI relates the close to the midpoint of the high/low range. Developed by William Blau in 1993. } \details{ If a High-Low-Close series is provided, the indicator is calculated using the high/low values. If a vector is provided, the calculation only uses that series. This allows stochastics to be calculated for: (1) series that have no HLC definition (e.g. foreign exchange), and (2) stochastic indicators (e.g. stochastic RSI - see examples). The \code{smooth} argument is the number of periods of internal smoothing to apply to the differences in the high-low-close range before calculating Fast K. Thanks to Stanley Neo for the suggestion. } \note{ The calculation for William's \%R is similar to that of stochastics' fast \%K. The value for fast \%K will be 0.5 whenever the highest high and lowest low are the same over the last \code{n} periods. The stochastic oscillator and SMI calculate relative value of the close versus the high/low range and the midpoint of the high/low range, respectively. The stochastic oscillator and the stochastic momentum index are interpreted similarly. Readings below 20 (above 80) are considered oversold (overbought). However, readings below 20 (above 80) are not necessarily bearish (bullish). Lane believed some of the best sell (buy) signals occurred when the oscillator moved from overbought (oversold) back below 80 (above 20). For the stochastic oscillator, buy (sell) signals can also be given when \%K crosses above (below) \%D. Crossover signals are quite frequent however, which may result in whipsaws. } \examples{ data(ttrc) stochOSC <- stoch(ttrc[,c("High","Low","Close")]) stochWPR <- WPR(ttrc[,c("High","Low","Close")]) plot(tail(stochOSC[,"fastK"], 100), type="l", main="Fast \%K and Williams \%R", ylab="", ylim=range(cbind(stochOSC, stochWPR), na.rm=TRUE) ) lines(tail(stochWPR, 100), col="blue") lines(tail(1-stochWPR, 100), col="red", lty="dashed") stoch2MA <- stoch( ttrc[,c("High","Low","Close")], maType=list(list(SMA), list(EMA, wilder=TRUE), list(SMA)) ) SMI3MA <- SMI(ttrc[,c("High","Low","Close")], maType=list(list(SMA), list(EMA, wilder=TRUE), list(SMA)) ) stochRSI <- stoch( RSI(ttrc[,"Close"]) ) } \references{ The following site(s) were used to code/document these indicators: \cr Stochastic Oscillator:\cr \url{https://www.fmlabs.com/reference/StochasticOscillator.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=106}\cr \url{https://www.linnsoft.com/techind/stochastics}\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:stochastic_oscillator_fast_slow_and_full}\cr \cr SMI:\cr \url{https://www.fmlabs.com/reference/default.htm?url=SMI.htm}\cr } \seealso{ See \code{\link{EMA}}, \code{\link{SMA}}, etc. for moving average options; and note Warning section. See \code{\link{WPR}} to compare it's results to fast \%K. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/ttrc.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/TTR-package.R \docType{data} \name{ttrc} \alias{ttrc} \title{Technical Trading Rule Composite data} \format{ The format is: \tabular{lll}{ Date: \tab Class 'Date' \tab 5480 5481 5482 5485 5486 ...\cr Open: \tab num \tab 3.18 3.09 3.11 3.09 3.10 ...\cr High: \tab num \tab 3.18 3.15 3.12 3.12 3.12 ...\cr Low: \tab num \tab 3.08 3.09 3.08 3.07 3.08 ...\cr Close: \tab num \tab 3.08 3.11 3.09 3.10 3.11 ...\cr Volume: \tab num \tab 1870906 3099506 2274157 2086758 2166348 ...\cr } } \source{ Randomly generated. } \description{ Historical Open, High, Low, Close, and Volume data for the periods January 2, 1985 to December 31, 2006. Randomly generated. } \details{ These data do not represent an actual security. They are provided so examples do not necessitate an internet connection. } \examples{ data(ttrc) plot(tail(ttrc[,"Close"],100), type="l") } \keyword{datasets} ================================================ FILE: man/ultimateOscillator.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/ultimateOscillator.R \name{ultimateOscillator} \alias{ultimateOscillator} \title{The Ultimate Oscillator} \usage{ ultimateOscillator(HLC, n = c(7, 14, 28), wts = c(4, 2, 1)) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices.} \item{n}{A vector of the number of periods to use for each average calculation.} \item{wts}{The weights applied to each average.} } \description{ The Ultimate Oscillator is a momentum oscillator designed to capture momentum across three different time frames. } \details{ Created by Larry Williams in 1976. } \examples{ data(ttrc) ult.osc <- ultimateOscillator(ttrc[,c("High","Low","Close")]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://school.stockcharts.com/doku.php?id=technical_indicators:ultimate_oscillator}\cr } \author{ Ivan Popivanov } \keyword{ts} ================================================ FILE: man/volatility.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/volatility.R \name{volatility} \alias{volatility} \alias{garman.klass} \alias{parkinson} \alias{rogers.satchell} \alias{gk.yz} \alias{yang.zhang} \title{Volatility} \usage{ volatility(OHLC, n = 10, calc = "close", N = 260, mean0 = FALSE, ...) } \arguments{ \item{OHLC}{Object that is coercible to xts or matrix and contains Open-High-Low-Close prices (or only Close prices, if \code{calc="close"}).} \item{n}{Number of periods for the volatility estimate.} \item{calc}{The calculation (type) of estimator to use.} \item{N}{Number of periods per year.} \item{mean0}{Use a mean of 0 rather than the sample mean.} \item{\dots}{Arguments to be passed to/from other methods.} } \value{ A object of the same class as \code{OHLC} or a vector (if \code{try.xts} fails) containing the chosen volatility estimator values. } \description{ Selected volatility estimators/indicators; various authors. } \details{ \itemize{ \item Close-to-Close Volatility (\code{calc="close"})\cr \deqn{ \sigma_{cl} = \sqrt{\frac{N}{n-2} \sum_{i=1}^{n-1}(r_i-\bar{r})^2} }{sqrt(N) * runSD(ROC(Cl), n-1)} \deqn{where\;\; r_i = \log \left(\frac{C_i}{C_{i-1}}\right) } \deqn{and\;\; \bar{r} = \frac{r_1+r_2+\ldots +r_{n-1}}{n-1} } \item OHLC Volatility: Garman and Klass (\code{calc="garman.klass"})\cr The Garman and Klass estimator for estimating historical volatility assumes Brownian motion with zero drift and no opening jumps (i.e. the opening = close of the previous period). This estimator is 7.4 times more efficient than the close-to-close estimator.\cr \deqn{ \sigma = \sqrt{ \frac{N}{n} \sum \left[ \textstyle\frac{1}{2}\displaystyle \left( \log \frac{H_i}{L_i} \right)^2 - (2\log 2-1) \left( \log \frac{C_i}{O_i} \right)^2 \right] } }{sqrt(N/n * runSum(0.5 * log(Hi/Lo)^2 - (2*log(2)-1) * log(Cl/Op)^2, n))} \item High-Low Volatility: Parkinson (\code{calc="parkinson"})\cr The Parkinson formula for estimating the historical volatility of an underlying based on high and low prices.\cr \deqn{ \sigma = \sqrt{ \frac{N}{4 n \times \log 2} \sum_{i=1}^{n} \left(\log \frac{H_i}{L_i}\right)^2} }{sqrt(N/(4*n*log(2)) * runSum(log(Hi/Lo)^2, n))} \item OHLC Volatility: Rogers and Satchell (\code{calc="rogers.satchell"})\cr The Roger and Satchell historical volatility estimator allows for non-zero drift, but assumed no opening jump.\cr \deqn{ \sigma = \sqrt{ \textstyle\frac{N}{n} \sum \left[ \log \textstyle\frac{H_i}{C_i} \times \log \textstyle\frac{H_i}{O_i} + \log \textstyle\frac{L_i}{C_i} \times \log \textstyle\frac{L_i}{O_i} \right] } }{sqrt(N/n * runSum(log(Hi/Cl) * log(Hi/Op) + log(Lo/Cl) * log(Lo/Op), n))} \item OHLC Volatility: Garman and Klass - Yang and Zhang (\code{calc="gk.yz"})\cr This estimator is a modified version of the Garman and Klass estimator that allows for opening gaps.\cr \deqn{ \sigma = \sqrt{ \textstyle\frac{N}{n} \sum \left[ \left( \log \textstyle\frac{O_i}{C_{i-1}} \right)^2 + \textstyle\frac{1}{2}\displaystyle \left( \log \textstyle\frac{H_i}{L_i} \right)^2 - (2 \times \log 2-1) \left( \log \textstyle\frac{C_i}{O_i} \right)^2 \right] } }{sqrt(N/n * runSum(log(Op/lag(Cl,1))^2 + 0.5 * log(Hi/Lo)^2 - (2*log(2)-1) * log(Cl/Op)^2 , n))} \item OHLC Volatility: Yang and Zhang (\code{calc="yang.zhang"})\cr The Yang and Zhang historical volatility estimator has minimum estimation error, and is independent of drift and opening gaps. It can be interpreted as a weighted average of the Rogers and Satchell estimator, the close-open volatility, and the open-close volatility. Users may override the default values of \eqn{\alpha} (1.34 by default) or \eqn{k} used in the calculation by specifying \code{alpha} or \code{k} in \code{\dots}, respectively. Specifying \code{k} will cause \code{alpha} to be ignored, if both are provided.\cr \deqn{ \sigma^2 = \sigma_o^2 + k\sigma_c^2 + (1-k)\sigma_{rs}^2 }{ s <- sqrt(s2o + k*s2c + (1-k)*(s2rs^2)) } \deqn{ \sigma_o^2 =\textstyle \frac{N}{n-1} \sum \left( \log \frac{O_i}{C_{i-1}}-\mu_o \right)^2 }{ s2o <- N * runVar(log(Op/lag(Cl,1)), n=n) } \deqn{ \mu_o=\textstyle \frac{1}{n} \sum \log \frac{O_i}{C_{i-1}} } \deqn{ \sigma_c^2 =\textstyle \frac{N}{n-1} \sum \left( \log \frac{C_i}{O_i}-\mu_c \right)^2 }{ s2c <- N * runVar(log(Cl/Op), n=n) } \deqn{ \mu_c=\textstyle \frac{1}{n} \sum \log \frac{C_i}{O_i} } \deqn{ \sigma_{rs}^2 = \textstyle\frac{N}{n} \sum \left( \log \textstyle\frac{H_i}{C_i} \times \log \textstyle\frac{H_i}{O_i} + \log \textstyle\frac{L_i}{C_i} \times \log \textstyle\frac{L_i}{O_i} \right) }{ s2rs <- volatility(OHLC, n, "rogers.satchell", N, ...) } \deqn{ k=\frac{\alpha-1}{alpha+\frac{n+1}{n-1}} }{ k <- (alpha-1) / (alpha + (n+1)/(n-1)) } } } \examples{ data(ttrc) ohlc <- ttrc[,c("Open","High","Low","Close")] vClose <- volatility(ohlc, calc="close") vClose0 <- volatility(ohlc, calc="close", mean0=TRUE) vGK <- volatility(ohlc, calc="garman") vParkinson <- volatility(ohlc, calc="parkinson") vRS <- volatility(ohlc, calc="rogers") } \references{ The following sites were used to code/document these indicators. All were created by Thijs van den Berg under the GNU Free Documentation License and were retrieved on 2008-04-20. The original links are dead, but can be accessed via internet archives.\cr \cr Close-to-Close Volatility (\code{calc="close"}):\cr \url{https://web.archive.org/web/20100421083157/http://www.sitmo.com/eq/172}\cr \cr OHLC Volatility: Garman Klass (\code{calc="garman.klass"}):\cr \url{https://web.archive.org/web/20100326172550/http://www.sitmo.com/eq/402}\cr \cr High-Low Volatility: Parkinson (\code{calc="parkinson"}):\cr \url{https://web.archive.org/web/20100328195855/http://www.sitmo.com/eq/173}\cr \cr OHLC Volatility: Rogers Satchell (\code{calc="rogers.satchell"}):\cr \url{https://web.archive.org/web/20091002233833/http://www.sitmo.com/eq/414}\cr \cr OHLC Volatility: Garman Klass - Yang Zhang (\code{calc="gk.yz"}):\cr \url{https://web.archive.org/web/20100326215050/http://www.sitmo.com/eq/409}\cr \cr OHLC Volatility: Yang Zhang (\code{calc="yang.zhang"}):\cr \url{https://web.archive.org/web/20100326215050/http://www.sitmo.com/eq/409}\cr } \seealso{ See \code{\link{TR}} and \code{\link{chaikinVolatility}} for other volatility measures. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: man/williamsAD.Rd ================================================ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/williamsAD.R \name{williamsAD} \alias{williamsAD} \title{Williams Accumulation / Distribution} \usage{ williamsAD(HLC) } \arguments{ \item{HLC}{Object that is coercible to xts or matrix and contains High-Low-Close prices.} } \value{ A object of the same class as \code{HLC} or a vector (if \code{try.xts} fails) containing the accumulation / distribution values. } \description{ The Williams Accumulation / Distribution (AD) line is a measure of market momentum. Developed by Larry Williams. } \details{ The Williams AD line differs from OBV and chaikinAD in that it doesn't take volume into account. } \note{ The Accumulation/Distribution Line is interpreted by looking for a divergence in the direction of the indicator relative to price. } \examples{ data(ttrc) ad <- williamsAD(ttrc[,c("High","Low","Close")]) } \references{ The following site(s) were used to code/document this indicator:\cr \url{https://www.fmlabs.com/reference/WilliamsAD.htm}\cr \url{https://www.metastock.com/Customer/Resources/TAAZ/?p=125}\cr } \seealso{ See \code{\link{OBV}}, \code{\link{chaikinAD}}, and \code{\link{ATR}}. } \author{ Joshua Ulrich } \keyword{ts} ================================================ FILE: src/adjRatios.c ================================================ /* * TTR: Technical Trading Rules * * Copyright (C) 2007-2013 Joshua M. Ulrich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include SEXP adjRatios (SEXP split, SEXP div, SEXP close) { /* Initialize REAL pointers to function arguments */ double *real_close = REAL(close); double *real_split = REAL(split); double *real_div = REAL(div); /* Initialize loop and PROTECT counters */ int i, P = 0; /* Initialize object length (NOTE: all arguments are the same length) */ int N = length(close); /* Initialize result R objects */ SEXP result; PROTECT(result = allocVector(VECSXP, 2)); P++; SEXP s_ratio; PROTECT(s_ratio = allocVector(REALSXP,N)); P++; SEXP d_ratio; PROTECT(d_ratio = allocVector(REALSXP,N)); P++; /* Initialize REAL pointers to R objects and set their last value to '1' */ double *rs_ratio = REAL(s_ratio); double *rd_ratio = REAL(d_ratio); rs_ratio[N-1] = 1; rd_ratio[N-1] = 1; /* Loop over split/div vectors from newest period to oldest */ for(i = N-1; i > 0; i--) { /* Carry newer ratio value backward */ if(ISNA(real_split[i])) { rs_ratio[i-1] = rs_ratio[i]; /* Update split ratio */ } else { rs_ratio[i-1] = rs_ratio[i] * real_split[i]; } /* Carry newer ratio value backward */ if(ISNA(real_div[i])) { rd_ratio[i-1] = rd_ratio[i]; } else { /* Update dividend ratio */ rd_ratio[i-1] = rd_ratio[i] * (1.0 - real_div[i] / real_close[i-1]); } } /* Assign results to list */ SET_VECTOR_ELT(result, 0, s_ratio); SET_VECTOR_ELT(result, 1, d_ratio); /* UNPROTECT R objects and return result */ UNPROTECT(P); return(result); } ================================================ FILE: src/aroon.c ================================================ /* * TTR: Technical Trading Rules * * Copyright (C) 2007-2013 Joshua M. Ulrich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ttr.h" SEXP aroon_max (SEXP x, SEXP n) { /* Initialize loop, loc, and PROTECT counters */ int i, j, loc=0, P=0; /* Ensure x argument is double */ if(TYPEOF(x) != REALSXP) { PROTECT(x = coerceVector(x, REALSXP)); P++; } /* Pointers to function arguments */ double *real_x = REAL(x); int int_n = asInteger(n); /* Input object length */ int nr = length(x); /* Initialize result R object */ SEXP result; PROTECT(result = allocVector(REALSXP, nr)); P++; double *real_result = REAL(result); /* check for non-leading NAs and get first non-NA location */ SEXP first = PROTECT(xts_na_check(x, ScalarLogical(TRUE))); P++; int int_first = asInteger(first); if(int_n + int_first > nr) error("not enough non-NA values"); double real_max = real_x[0]; /* set leading NAs and find initial max value */ for (i = 0; i < int_first + int_n-1; i++) { real_result[i] = NA_REAL; if(real_x[i] >= real_max) { real_max = real_x[i]; /* set max value */ loc = 0; /* set max location in window */ } loc++; continue; } /* Loop over non-NA input values */ for (i = int_first + int_n-1; i < nr; i++) { /* if the max leaves the window */ if(loc > int_n) { /* find the max over the (n+1) window */ real_max = real_x[i]; loc = 0; //for(j=0; j real_max) { real_max = real_x[i-j]; loc = j; } } } else { /* if the new value is the new max */ if(real_x[i] >= real_max) { real_max = real_x[i]; loc = 0; } } /* set result, increment location */ real_result[i] = (100.0 * (int_n - loc)) / int_n; loc++; } /* UNPROTECT R objects and return result */ UNPROTECT(P); return(result); } ================================================ FILE: src/init.c ================================================ /* * TTR: Technical Trading Rules * * Copyright (C) 2007-2017 Joshua M. Ulrich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* Includes and defines from WRE Section 5.4.2 */ #include "ttr.h" #include #include /* for NULL */ #include #define CALLDEF(name, n) {#name, (DL_FUNC) &name, n} /* define xts imports */ SEXP (*xts_na_check)(SEXP,SEXP); static const R_CallMethodDef CallEntries[] = { CALLDEF(adjRatios, 3), CALLDEF(aroon_max, 2), CALLDEF(ema, 4), CALLDEF(evwma, 3), CALLDEF(sar, 3), CALLDEF(ttr_rollPercentRank, 4), CALLDEF(ttr_zigzag, 6), CALLDEF(wilderSum, 2), CALLDEF(wma, 3), CALLDEF(zlema, 3), CALLDEF(runsum, 2), CALLDEF(runrange, 2), CALLDEF(runmedian, 4), CALLDEF(runmad, 6), CALLDEF(runcov, 5), {NULL, NULL, 0} }; /* Restrict .Call etc to use only registered symbols */ void R_init_TTR(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); R_forceSymbols(dll, TRUE); /* imports from xts C code */ xts_na_check = (SEXP(*)(SEXP,SEXP)) R_GetCCallable("xts", "naCheck"); } ================================================ FILE: src/moving_averages.c ================================================ /* * TTR: Technical Trading Rules * * Copyright (C) 2007-2013 Joshua M. Ulrich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ttr.h" SEXP ema (SEXP x, SEXP n, SEXP ratio, SEXP wilder) { /* Initialize loop and PROTECT counters */ int i, P=0; /* ensure that 'x' is double */ if(TYPEOF(x) != REALSXP) { PROTECT(x = coerceVector(x, REALSXP)); P++; } double *d_x = REAL(x); if(ncols(x) > 1) { error("ncol(x) > 1; EMA only supports univariate 'x'"); } int i_n = asInteger(n); double d_ratio = asReal(ratio); if(R_NilValue == n || i_n <= 0) { if(R_NilValue == ratio || d_ratio <= 0.0) { error("either 'n' or 'ratio' must be specified and > 0\n'n' is %d and 'ratio' is %1.6f", i_n, d_ratio); } else { /* If ratio is specified, and n is not, set n to approx 'correct' * value backed out from ratio */ i_n = (int)(2.0 / d_ratio - 1.0); } } else { /* Determine decay ratio */ if(R_NilValue == ratio) { int isWilder = asInteger(wilder); d_ratio = (isWilder) ? 1.0 / i_n : 2.0 / (i_n + 1); } else { /* ratio != NULL -> warn that 'n' will be used instead */ warning("both 'n' and 'ratio' are specified; using 'n'"); } } /* Input object length */ int nr = nrows(x); /* Initialize result R object */ SEXP result; PROTECT(result = allocVector(REALSXP,nr)); P++; double *d_result = REAL(result); /* check for non-leading NAs and get first non-NA location */ SEXP _first = PROTECT(xts_na_check(x, ScalarLogical(TRUE))); P++; int first = INTEGER(_first)[0]; if(i_n + first > nr) { error("not enough non-NA values"); } /* Set leading NAs in output */ for(i = 0; i < first; i++) { d_result[i] = NA_REAL; } /* Raw mean to start EMA */ double seed = 0.0; for(i = first; i < first + i_n; i++) { d_result[i] = NA_REAL; seed += d_x[i] / i_n; } d_result[first + i_n - 1] = seed; /* Loop over non-NA input values */ for(i = first + i_n; i < nr; i++) { d_result[i] = d_x[i] * d_ratio + d_result[i-1] * (1-d_ratio); } /* UNPROTECT R objects and return result */ UNPROTECT(P); return(result); } SEXP evwma (SEXP pr, SEXP vo, SEXP n) { /* Initialize loop and PROTECT counters */ int i, P=0; /* ensure that 'pr' is double */ if(TYPEOF(pr) != REALSXP) { PROTECT(pr = coerceVector(pr, REALSXP)); P++; } /* ensure that 'vo' is double */ if(TYPEOF(vo) != REALSXP) { PROTECT(vo = coerceVector(vo, REALSXP)); P++; } /* Pointers to function arguments */ double *d_pr = REAL(pr); double *d_vo = REAL(vo); int i_n = asInteger(n); /* Input object length */ int nr = nrows(pr); /* Initialize result R object */ SEXP result; PROTECT(result = allocVector(REALSXP,nr)); P++; double *d_result = REAL(result); /* check for non-leading NAs and get first non-NA location */ SEXP _first_pr = PROTECT(xts_na_check(pr, ScalarLogical(TRUE))); P++; int first_pr = asInteger(_first_pr); if(i_n + first_pr > nr) { error("not enough non-NA values in 'price'"); } SEXP _first_vo = PROTECT(xts_na_check(vo, ScalarLogical(TRUE))); P++; int first_vo = asInteger(_first_vo); if(i_n + first_vo > nr) { error("not enough non-NA values in 'volume'"); } int first = first_pr > first_vo ? first_pr : first_vo; int begin = first + i_n - 1; /* Set leading NAs in output */ for(i = 0; i < begin; i++) { d_result[i] = NA_REAL; } /* First non-NA result is the first non-NA value of 'x' */ d_result[begin] = d_pr[begin]; /* Initialize volume sum */ double volSum = 0.0; for(i = first; i < begin+1; i++) { volSum += d_vo[i]; } /* Loop over the rest of the values */ for(i = begin + 1; i < nr; i++) { volSum = volSum + d_vo[i] - d_vo[i-i_n]; d_result[i] = ((volSum-d_vo[i])*d_result[i-1]+d_vo[i]*d_pr[i])/volSum; } /* UNPROTECT R objects and return result */ UNPROTECT(P); return(result); } SEXP wma (SEXP x, SEXP w, SEXP n) { /* Initialize loop and PROTECT counters */ int i, j, P=0; /* ensure that 'x' is double */ if(TYPEOF(x) != REALSXP) { PROTECT(x = coerceVector(x, REALSXP)); P++; } /* ensure that 'w' is double */ if(TYPEOF(w) != REALSXP) { PROTECT(w = coerceVector(w, REALSXP)); P++; } int i_n = asInteger(n); /* Pointers to function arguments */ double *d_x = REAL(x); double *d_w = REAL(w); /* Input object length */ int nr = nrows(x); /* Initialize result R object */ SEXP result; PROTECT(result = allocVector(REALSXP,nr)); P++; double *d_result = REAL(result); /* check for non-leading NAs and get first non-NA location */ SEXP _first = PROTECT(xts_na_check(x, ScalarLogical(TRUE))); P++; int first = INTEGER(_first)[0]; if(i_n + first > nr) { error("not enough non-NA values"); } int begin = first + i_n - 1; /* Set leading NAs in output */ for(i = 0; i < begin; i++) { d_result[i] = NA_REAL; } /* Sum of weights (w does not have NA) */ double wtsum = 0.0; for(j = 0; j < i_n; j++) { if(ISNA(d_w[j])) { error("wts cannot contain NA"); } wtsum += d_w[j]; } /* Loop over non-NA input values */ for(i = begin; i < nr; i++) { double num = 0.0; int ni = i - i_n + 1; for(j = 0; j < i_n; j++) { num += d_x[ni+j] * d_w[j]; } d_result[i] = num / wtsum; } /* UNPROTECT R objects and return result */ UNPROTECT(P); return(result); } SEXP zlema (SEXP x, SEXP n, SEXP ratio) { /* Initialize loop and PROTECT counters */ int i, P=0; /* ensure that 'x' is double */ if(TYPEOF(x) != REALSXP) { PROTECT(x = coerceVector(x, REALSXP)); P++; } double *d_x = REAL(x); if(ncols(x) > 1) { error("ncol(x) > 1; ZLEMA only supports univariate 'x'"); } int i_n = asInteger(n); double d_ratio = asReal(ratio); if(R_NilValue == n || i_n <= 0) { if(R_NilValue == ratio || d_ratio <= 0.0) { error("either 'n' or 'ratio' must be specified and > 0\n'n' is %d and 'ratio' is %1.6f", i_n, d_ratio); } else { /* If ratio is specified, and n is not, set n to approx 'correct' * value backed out from ratio */ i_n = (int)(2.0 / d_ratio - 1.0); } } else { /* Determine decay ratio */ if(R_NilValue == ratio) { d_ratio = 2.0 / (i_n + 1); } else { /* ratio != NULL -> warn that 'n' will be used instead */ warning("both 'n' and 'ratio' are specified; using 'n'"); } } /* Input object length */ int nr = nrows(x); /* Initialize result R object */ SEXP result; PROTECT(result = allocVector(REALSXP,nr)); P++; double *d_result = REAL(result); /* check for non-leading NAs and get first non-NA location */ SEXP _first = PROTECT(xts_na_check(x, ScalarLogical(TRUE))); P++; int first = INTEGER(_first)[0]; if(i_n + first > nr) { error("not enough non-NA values"); } /* Set leading NAs in output */ for(i = 0; i < first; i++) { d_result[i] = NA_REAL; } /* Raw mean to start EMA */ double seed = 0.0; for(i = first; i < first + i_n; i++) { d_result[i] = NA_REAL; seed += d_x[i] / i_n; } d_result[first + i_n - 1] = seed; double lag = 1.0 / d_ratio; double wt = fmod(lag, 1.0); double w1 = 1.0 - wt; double r1 = 1.0 - d_ratio; /* Loop over non-NA input values */ for(i = first + i_n; i < nr; i++) { int loc = (int)(i - lag); double value = 2 * d_x[i] - (w1 * d_x[loc] + wt * d_x[loc+1]); d_result[i] = d_ratio * value + r1 * d_result[i-1]; } /* UNPROTECT R objects and return result */ UNPROTECT(P); return(result); } ================================================ FILE: src/percent_rank.c ================================================ /* * TTR: Technical Trading Rules * * Copyright (C) 2012-2017 Charlie Friedemann, Joshua M. Ulrich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include double calc_n_less(double* x, double mult, int i, int j1) { double n_less = mult; /* Loop over window */ for (int j = j1; j < i; j++) { double diff = x[j] - x[i]; if (diff < 0) { n_less = n_less + 1.0; } else if (fabs(diff) < 1e-8) { n_less = n_less + mult; } } return n_less; } /* Calculate a running/rolling percent rank, * or a cumulative version */ SEXP ttr_rollPercentRank(SEXP _x, SEXP _n, SEXP _cumul, SEXP _mult) { int i, P = 0; /* ensure correct types */ if (TYPEOF(_x) != REALSXP) { PROTECT(_x = coerceVector(_x, REALSXP)); P++; } double *d_x = REAL(_x); int n = asInteger(_n); int cumul = asLogical(_cumul); double mult = asReal(_mult); int nr = nrows(_x); /* Initialize result R object */ SEXP result; PROTECT(result = allocVector(REALSXP, nr)); P++; double *d_result = REAL(result); /* Find first non-NA input value */ int beg = n - 1; int n_na = 0; for (i = 0; i < beg; i++) { /* first 'n' observations are set to NA */ d_result[i] = NA_REAL; /* Account for leading NAs in input */ if (ISNA(d_x[i])) { beg++; n_na++; if (beg >= nr) { error("runPercentRank input has %d rows, %d NA. Cannot calculate result with n = %d.", nr, n_na, n); } } } /* Loop over non-NA input values */ if (cumul) { d_result[beg] = mult; for (i = beg+1; i < nr; i++) { double n_less = calc_n_less(d_x, mult, i, 0); d_result[i] = n_less / (i + 1); } } else { for (i = beg; i < nr; i++) { double n_less = calc_n_less(d_x, mult, i, i-n+1); d_result[i] = n_less / n; } } UNPROTECT(P); return(result); } ================================================ FILE: src/runfun.c ================================================ /* * TTR: Technical Trading Rules * * Copyright (C) 2007-2018 Joshua M. Ulrich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include /* for memcpy */ #include "ttr.h" SEXP runsum(SEXP _x, SEXP _n) { int i, P = 0; /* ensure that 'x' is double */ if (TYPEOF(_x) != REALSXP) { _x = PROTECT(coerceVector(_x, REALSXP)); P++; } double *x = REAL(_x); int n = asInteger(_n); /* Input object length */ int nr = nrows(_x); /* Initialize result R object */ SEXP _result = PROTECT(allocVector(REALSXP, nr)); P++; double *result = REAL(_result); /* check for non-leading NAs and get first non-NA location */ SEXP _first = PROTECT(xts_na_check(_x, ScalarLogical(TRUE))); P++; int first = INTEGER(_first)[0]; if (n + first > nr) { error("not enough non-NA values"); } /* Set leading NAs in output */ for (i = 0; i < first; i++) { result[i] = NA_REAL; } /* Raw sum to start running sum */ double seed = 0.0; for (i = first; i < first + n; i++) { result[i] = NA_REAL; seed += x[i]; } result[first + n - 1] = seed; /* Loop over non-NA input values */ for (i = first + n; i < nr; i++) { result[i] = result[i-1] + x[i] - x[i-n]; } /* UNPROTECT R objects and return result */ UNPROTECT(P); return _result; } SEXP runrange(SEXP _x, SEXP _n) { int i, j, P = 0; /* ensure x is double */ if (TYPEOF(_x) != REALSXP) { _x = PROTECT(coerceVector(_x, REALSXP)); P++; } double *x = REAL(_x); int n = asInteger(_n); /* input length */ int nr = nrows(_x); /* allocate result: 2 columns (min, max) */ SEXP _result = PROTECT(allocMatrix(REALSXP, nr, 2)); P++; double *result = REAL(_result); /* check for non-leading NAs and get first non-NA location */ SEXP _first = PROTECT(xts_na_check(_x, ScalarLogical(TRUE))); P++; int first = INTEGER(_first)[0]; if (n + first > nr) { error("not enough non-NA values"); } /* leading NAs */ for (i = 0; i < first; i++) { result[i] = NA_REAL; /* min */ result[i + nr] = NA_REAL; /* max */ } /* initialize first window */ double lmin = x[first], lmax = x[first]; for (i = first; i < first + n; i++) { result[i] = NA_REAL; result[i + nr] = NA_REAL; if (x[i] < lmin) lmin = x[i]; if (x[i] > lmax) lmax = x[i]; } result[first + n - 1] = lmin; result[first + n - 1 + nr] = lmax; /* main loop */ for (i = first + n; i < nr; i++) { lmin = x[i]; lmax = x[i]; for (j = 1; j < n; j++) { double v = x[i - j]; if (v < lmin) lmin = v; if (v > lmax) lmax = v; } result[i] = lmin; result[i + nr] = lmax; } UNPROTECT(P); return _result; } typedef double (*tiebreaker)(const double, const double); static inline double tiebreaker_lt(const double a, const double b) { return (a < b) ? a : b; } static inline double tiebreaker_gt(const double a, const double b) { return (a > b) ? a : b; } static inline double tiebreaker_eq(const double a, const double b) { return (a + b) / 2.0; } static inline double ttr_median(double *x, int i, int n, tiebreaker tie_func) { /* NOTE: 'i' and 'n' are 1-based */ int N = n-i+1; // number of observations in the window int flag = N-2*(N/2); // even number of observations? int mid = (i-1)+N/2-1; // 0-based index midpoint R_qsort(x, i, n); double median = (flag) ? x[mid+1] : tie_func(x[mid] , x[mid+1]); return median; } SEXP runmedian(SEXP _x, SEXP _n, SEXP _tiebreak, SEXP _cumulative) { int i, P = 0; /* ensure that 'x' is double */ if (TYPEOF(_x) != REALSXP) { _x = PROTECT(coerceVector(_x, REALSXP)); P++; } double *x = REAL(_x); int n = asInteger(_n); int tiebreak = asInteger(_tiebreak); int cumulative = asLogical(_cumulative); /* Input object length */ int nr = nrows(_x); /* Initialize result R object */ SEXP _result = PROTECT(allocVector(REALSXP, nr)); P++; double *result = REAL(_result); /* check for non-leading NAs and get first non-NA location */ SEXP _first = PROTECT(xts_na_check(_x, ScalarLogical(TRUE))); P++; int first = INTEGER(_first)[0]; if (n + first > nr) { error("not enough non-NA values"); } /* Set leading NAs in output */ for (i = 0; i < first + n; i++) { result[i] = NA_REAL; } tiebreaker tie_func = NULL; if (tiebreak == 0) { tie_func = tiebreaker_eq; } else if (tiebreak < 0) { tie_func = tiebreaker_lt; } else if (tiebreak > 0) { tie_func = tiebreaker_gt; } SEXP _window; double *window; int first_i = first + n - 1; if (cumulative) { _window = PROTECT(duplicate(_x)); P++; window = REAL(_window); for (i = first_i; i < nr; i++) { result[i] = ttr_median(window, first+1, i+1, tie_func); } } else { _window = PROTECT(allocVector(REALSXP, n)); P++; window = REAL(_window); for (i = first_i; i < nr; i++) { memcpy(window, &x[i-n+1], n * sizeof(double)); result[i] = ttr_median(window, 1, n, tie_func); } } /* UNPROTECT R objects and return result */ UNPROTECT(P); return _result; } static inline double ttr_mean(const double *x, const int n) { double mean = x[0] / n; int i; for (i = 1; i < n; i++) { mean += x[i] / n; } return mean; } SEXP runmad(SEXP _x, SEXP _center, SEXP _n, SEXP _type, SEXP _tiebreak, SEXP _cumulative) { int i, j, P = 0; /* ensure 'x' and 'center' are double */ if (TYPEOF(_x) != REALSXP) { _x = PROTECT(coerceVector(_x, REALSXP)); P++; } if (TYPEOF(_center) != REALSXP) { _center = PROTECT(coerceVector(_center, REALSXP)); P++; } double *x = REAL(_x); double *center = REAL(_center); int n = asInteger(_n); int type = asInteger(_type); int tiebreak = asInteger(_tiebreak); int cumulative = asLogical(_cumulative); /* Input object length */ int nr = nrows(_x); if (nr != nrows(_center)) { error("'x' and 'center' must have the same number of observations"); } /* Initialize result R object */ SEXP _result = PROTECT(allocVector(REALSXP, nr)); P++; double *result = REAL(_result); /* check for non-leading NAs and get first non-NA location */ SEXP _first = PROTECT(xts_na_check(_x, ScalarLogical(TRUE))); P++; int first = INTEGER(_first)[0]; if (n + first > nr) { error("not enough non-NA values in 'x'"); } /* Set leading NAs in output */ for (i = 0; i < first + n; i++) { result[i] = NA_REAL; } tiebreaker tie_func = NULL; if (tiebreak == 0) { tie_func = tiebreaker_eq; } else if (tiebreak < 0) { tie_func = tiebreaker_lt; } else if (tiebreak > 0) { tie_func = tiebreaker_gt; } SEXP _window; double *window; int first_i = first + n - 1; if (cumulative) { _window = PROTECT(duplicate(_x)); P++; window = REAL(_window); if (type) { for (i = first_i; i < nr; i++) { int N = i-first+1; for (j = 0; j < N; j++) { window[j] = fabs(x[i-j] - center[i]); } result[i] = ttr_median(window, 1, N, tie_func); } } else { for (i = first_i; i < nr; i++) { for (j = 0; j <= i; j++) { window[j] = fabs(x[i-j] - center[i]); } result[i] = ttr_mean(window, i+1); } } } else { _window = PROTECT(allocVector(REALSXP, n)); P++; window = REAL(_window); if (type) { for (i = first_i; i < nr; i++) { for (j = 0; j < n; j++) { window[j] = fabs(x[i-j] - center[i]); } result[i] = ttr_median(window, 1, n, tie_func); } } else { for (i = first_i; i < nr; i++) { for (j = 0; j < n; j++) { window[j] = fabs(x[i-j] - center[i]); } result[i] = ttr_mean(window, n); } } } /* UNPROTECT R objects and return result */ UNPROTECT(P); return _result; } SEXP runcov(SEXP _x, SEXP _y, SEXP _n, SEXP _sample, SEXP _cumulative) { int i, j, P = 0; /* ensure 'x' and 'y' are double */ if (TYPEOF(_x) != REALSXP) { _x = PROTECT(coerceVector(_x, REALSXP)); P++; } if (TYPEOF(_y) != REALSXP) { _y = PROTECT(coerceVector(_y, REALSXP)); P++; } double *x = REAL(_x); double *y = REAL(_y); int n = asInteger(_n); int cumulative = asLogical(_cumulative); int sample = asLogical(_sample); /* Input object length */ int nr = nrows(_x); if (nr != nrows(_y)) { error("'x' and 'y' must have the same number of observations"); } /* Initialize result R object */ SEXP _result = PROTECT(allocVector(REALSXP, nr)); P++; double *result = REAL(_result); /* check for non-leading NAs and get first non-NA location */ SEXP _first_x = PROTECT(xts_na_check(_x, ScalarLogical(TRUE))); P++; int first_x = INTEGER(_first_x)[0]; if (n + first_x > nr) { error("not enough non-NA values in 'x'"); } SEXP _first_y = PROTECT(xts_na_check(_y, ScalarLogical(TRUE))); P++; int first_y = INTEGER(_first_y)[0]; if (n + first_y > nr) { error("not enough non-NA values in 'y'"); } int first = (first_x > first_y) ? first_x : first_y; int first_i = first + n - 1; /* Set leading NAs in output */ for (i = 0; i < first_i; i++) { result[i] = NA_REAL; } SEXP _window; double *window, mu_x, mu_y; if (cumulative) { double sum_x = 0.0; double sum_y = 0.0; // Initialize means for (i = first; i < first_i; i++) { sum_x += x[i]; sum_y += y[i]; } mu_x = sum_x / (first+1); mu_y = sum_y / (first+1); for (i = first_i; i < nr; i++) { double n_window = (double)(i-first_i+n); sum_x += x[i]; sum_y += y[i]; mu_x = sum_x / n_window; mu_y = sum_y / n_window; result[i] = 0.0; for (j = first; j <= i; j++) { result[i] += (x[j] - mu_x) * (y[j] - mu_y); } result[i] /= sample ? (n_window-1.0) : n_window; } /* Set first non-NA element to NA to match var() and sd() * because var/sd of 1 observation is not defined */ result[first] = NA_REAL; } else { double denom = sample ? (n-1) : n; if (n == 1) { warning("(co-)variance is not defined for one observation; returning NA"); for (i = first_i; i < nr; i++) { result[i] = NA_REAL; } } else { _window = PROTECT(allocVector(REALSXP, n)); P++; window = REAL(_window); size_t window_size = n * sizeof(double); for (i = first_i; i < nr; i++) { memcpy(window, &x[i-n+1], window_size); mu_x = ttr_mean(window, n); memcpy(window, &y[i-n+1], window_size); mu_y = ttr_mean(window, n); result[i] = 0.0; for (j = 0; j < n; j++) { result[i] += (x[i-j] - mu_x) * (y[i-j] - mu_y); } result[i] /= denom; } } } /* UNPROTECT R objects and return result */ UNPROTECT(P); return _result; } ================================================ FILE: src/sar.c ================================================ /* * TTR: Technical Trading Rules * * Copyright (C) 2007-2013 Joshua M. Ulrich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include SEXP sar (SEXP hi, SEXP lo, SEXP xl) { /* Initialize loop and PROTECT counters */ int i, P=0; /* Ensure all arguments are double */ if(TYPEOF(hi) != REALSXP) { PROTECT(hi = coerceVector(hi, REALSXP)); P++; } if(TYPEOF(lo) != REALSXP) { PROTECT(lo = coerceVector(lo, REALSXP)); P++; } if(TYPEOF(xl) != REALSXP) { PROTECT(xl = coerceVector(xl, REALSXP)); P++; } /* Pointers to function arguments */ double *d_hi = REAL(hi); double *d_lo = REAL(lo); double *d_xl = REAL(xl); /* check acceleration factors */ if(d_xl[0] <= 0) error("acceleration factor must be > 0"); if(d_xl[1] <= d_xl[0]) error("maximum acceleration must be > acceleration factor"); /* Input object length */ int nr = nrows(hi); /* Initialize result R object */ SEXP sar; PROTECT(sar = allocMatrix(REALSXP, nr, 1)); P++; double *d_sar = REAL(sar); /* Find first non-NA value */ int beg = 1; for(i=0; i < nr; i++) { if( ISNA(d_hi[i]) || ISNA(d_lo[i]) ) { d_sar[i] = NA_REAL; beg++; } else { break; } } /* Initialize values needed by the routine */ int sig0 = 1, sig1 = 0; double xpt0 = d_hi[beg-1], xpt1 = 0; double af0 = d_xl[0], af1 = 0; double lmin, lmax; double hi1 = d_hi[beg-1]; double lo1 = d_lo[beg-1]; double mu1 = (hi1 + lo1) / 2.0; /* Use stdev of first high and low as the initial gap */ double initGap = sqrt((hi1-mu1)*(hi1-mu1) + (lo1-mu1)*(lo1-mu1)); d_sar[beg-1] = d_lo[beg-1]-initGap; for(i=beg; i < nr; i++) { /* Increment signal, extreme point, and acceleration factor */ sig1 = sig0; xpt1 = xpt0; af1 = af0; /* Local extrema */ lmin = fmin(d_lo[i-1], d_lo[i]); lmax = fmax(d_hi[i-1], d_hi[i]); /* Create signal and extreme price vectors */ if( sig1 == 1 ) { /* Previous buy signal */ sig0 = (d_lo[i] > d_sar[i-1]) ? 1 : -1; /* New signal */ xpt0 = fmax(lmax, xpt1); /* New extreme price */ } else { /* Previous sell signal */ sig0 = (d_hi[i] < d_sar[i-1]) ? -1 : 1; /* New signal */ xpt0 = fmin(lmin, xpt1); /* New extreme price */ } /* * Calculate acceleration factor (af) * and stop-and-reverse (sar) vector */ /* No signal change */ if( sig0 == sig1 ) { /* Initial calculations */ d_sar[i] = d_sar[i-1] + ( xpt1 - d_sar[i-1] ) * af1; af0 = (af1 == d_xl[1]) ? d_xl[1] : (d_xl[0] + af1); /* Current buy signal */ if( sig0 == 1 ) { af0 = (xpt0 > xpt1) ? af0 : af1; /* Update acceleration factor */ d_sar[i] = fmin(d_sar[i],lmin); /* Determine sar value */ } /* Current sell signal */ else { af0 = (xpt0 < xpt1) ? af0 : af1; /* Update acceleration factor */ d_sar[i] = fmax(d_sar[i],lmax); /* Determine sar value */ } } /* New signal */ else { af0 = d_xl[0]; /* reset acceleration factor */ d_sar[i] = xpt0; /* set sar value */ } } /* UNPROTECT R objects and return result */ UNPROTECT(P); return(sar); } ================================================ FILE: src/ttr.h ================================================ #ifndef _TTR_H_ #define _TTR_H_ #include /* declare functions called via .Call() */ SEXP adjRatios(SEXP, SEXP, SEXP); SEXP aroon_max(SEXP, SEXP); SEXP ema(SEXP, SEXP, SEXP, SEXP); SEXP evwma(SEXP, SEXP, SEXP); SEXP sar(SEXP, SEXP, SEXP); SEXP ttr_rollPercentRank(SEXP, SEXP, SEXP, SEXP); SEXP ttr_zigzag(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); SEXP wilderSum(SEXP, SEXP); SEXP wma(SEXP, SEXP, SEXP); SEXP zlema(SEXP, SEXP, SEXP); SEXP runsum(SEXP, SEXP); SEXP runrange(SEXP, SEXP); SEXP runmedian(SEXP, SEXP, SEXP, SEXP); SEXP runmad(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); SEXP runcov(SEXP, SEXP, SEXP, SEXP, SEXP); /* declare xts imports */ extern SEXP (*xts_na_check)(SEXP, SEXP); #endif ================================================ FILE: src/wilderSum.c ================================================ /* * TTR: Technical Trading Rules * * Copyright (C) 2007-2013 Joshua M. Ulrich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include SEXP wilderSum (SEXP x, SEXP n) { /* Initialize loop and PROTECT counters */ int i, P=0; /* assure that 'x' is double */ if(TYPEOF(x) != REALSXP) { PROTECT(x = coerceVector(x, REALSXP)); P++; } /* Pointers to function arguments */ double *d_x = REAL(x); int i_n = asInteger(n); /* Input object length */ int nr = nrows(x); /* Initialize result R object */ SEXP result; PROTECT(result = allocVector(REALSXP,nr)); P++; double *d_result = REAL(result); /* Find first non-NA input value */ int beg = i_n - 1; double sum = 0; for(i = 0; i < beg; i++) { /* Account for leading NAs in input */ if(ISNA(d_x[i])) { d_result[i] = NA_REAL; beg++; d_result[beg] = 0; continue; } /* Set leading NAs in output */ if(i < beg) { d_result[i] = NA_REAL; } /* Calculate raw sum to start */ sum += d_x[i]; } d_result[beg] = d_x[i] + sum * (i_n-1)/i_n; /* Loop over non-NA input values */ for(i = beg+1; i < nr; i++) { d_result[i] = d_x[i] + d_result[i-1] * (i_n-1)/i_n; } /* UNPROTECT R objects and return result */ UNPROTECT(P); return(result); } ================================================ FILE: src/zigzag.c ================================================ /* * TTR: Technical Trading Rules * * Copyright (C) 2007-2017 Joshua M. Ulrich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include /* price and its array index */ typedef struct { double price; int index; } price_and_index; SEXP ttr_zigzag (SEXP _high, SEXP _low, SEXP _change, SEXP _percent, SEXP _retrace, SEXP _last_extreme) { double* high = REAL(_high); double* low = REAL(_low); double change = asReal(_change); int use_percent = asLogical(_percent); int use_retrace = asLogical(_retrace); int use_last_ex = asLogical(_last_extreme); if (use_percent) change = change / 100.0; int n = length(_high); SEXP _zigzag = PROTECT(allocVector(REALSXP, n)); double* zigzag = REAL(_zigzag); price_and_index reference, inflection; reference.price = (high[0] + low[0]) / 2; reference.index = 0; inflection.price = (high[1] + low[1]) / 2; inflection.index = 1; double extreme_min, extreme_max, local_min, local_max; int signal = 0; for (int i = 1; i < n; i++) { /* Initialize all zigzag values to NA */ zigzag[i] = NA_REAL; if (use_percent) { /* If % change given (absolute move) */ extreme_min = inflection.price * (1.0 - change); extreme_max = inflection.price * (1.0 + change); } else { /* If $ change given (only absolute moves make sense) */ extreme_min = inflection.price - change; extreme_max = inflection.price + change; } /* Find local maximum and minimum */ local_max = inflection.price > high[i] ? inflection.price : high[i]; local_min = inflection.price < low[i] ? inflection.price : low[i]; /* Find first trend */ if (signal == 0) { if (use_retrace) { /* Retrace prior move */ signal = (inflection.price >= reference.price) ? 1 : -1; } else { /* Absolute move */ if (local_min <= extreme_min) { /* Confirmed Downtrend */ signal = -1; } if (local_max >= extreme_max) { /* Confirmed Uptrend */ signal = 1; } } } /* Downtrend */ if (signal == -1) { /* New Minimum */ if (low[i] == local_min) { /* Last Extreme */ if (use_last_ex) { inflection.price = low[i]; inflection.index = i; } else { /* First Extreme */ if (low[i] != low[i-1]) { inflection.price = low[i]; inflection.index = i; } } } /* Retrace prior move */ if (use_retrace) { extreme_max = inflection.price + ((reference.price - inflection.price) * change); } /* Trend Reversal */ if (high[i] >= extreme_max) { zigzag[reference.index] = reference.price; reference = inflection; inflection.price = high[i]; inflection.index = i; signal = 1; continue; } } /* Uptrend */ if (signal == 1) { /* New Maximum */ if (high[i] == local_max) { /* Last Extreme */ if (use_last_ex) { inflection.price = high[i]; inflection.index = i; } else { /* First Extreme */ if (high[i] != high[i-1]) { inflection.price = high[i]; inflection.index = i; } } } /* Retrace prior move */ if (use_retrace) { extreme_min = inflection.price - ((inflection.price - reference.price) * change); } /* Trend Reversal */ if (low[i] <= extreme_min) { zigzag[reference.index] = reference.price; reference = inflection; inflection.price = low[i]; inflection.index = i; signal = -1; continue; } } } zigzag[reference.index] = reference.price; zigzag[inflection.index] = inflection.price; UNPROTECT(1); return _zigzag; } ================================================ FILE: tests/tinytest.R ================================================ # run package unit tests if (requireNamespace("tinytest", quietly = TRUE)) { suppressPackageStartupMessages(library("TTR")) use_color <- as.logical(Sys.getenv("_PKG_TINYTEST_COLOR_", FALSE)) verbosity <- as.integer(Sys.getenv("_PKG_TINYTEST_VERBOSE_", 1)) cat("tinytest colored output:", use_color, "\ntinytest verbosity:", verbosity, "\n") tinytest::test_package("TTR", color = use_color, verbose = verbosity) }