├── .editorconfig
├── .github
├── FUNDING.yml
└── workflows
│ └── dotnet.yml
├── .gitignore
├── LICENSE
├── README.md
├── Tulip.sln
├── src
└── Tulip.NETCore
│ ├── ArrayExtensions.cs
│ ├── AssemblyInfo.cs
│ ├── GlobalUsings.cs
│ ├── Indicator.cs
│ ├── Indicators.cs
│ ├── Indicators
│ ├── TI_Abs.cs
│ ├── TI_Acos.cs
│ ├── TI_Ad.cs
│ ├── TI_Add.cs
│ ├── TI_Adosc.cs
│ ├── TI_Adx.cs
│ ├── TI_Adxr.cs
│ ├── TI_Ao.cs
│ ├── TI_Apo.cs
│ ├── TI_Aroon.cs
│ ├── TI_AroonOsc.cs
│ ├── TI_Asin.cs
│ ├── TI_Atan.cs
│ ├── TI_Atr.cs
│ ├── TI_AvgPrice.cs
│ ├── TI_Bbands.cs
│ ├── TI_Bop.cs
│ ├── TI_Cci.cs
│ ├── TI_Ceil.cs
│ ├── TI_Cmo.cs
│ ├── TI_Cos.cs
│ ├── TI_Cosh.cs
│ ├── TI_Crossany.cs
│ ├── TI_Crossover.cs
│ ├── TI_Cvi.cs
│ ├── TI_Decay.cs
│ ├── TI_Dema.cs
│ ├── TI_Di.cs
│ ├── TI_Div.cs
│ ├── TI_Dm.cs
│ ├── TI_Dpo.cs
│ ├── TI_Dx.cs
│ ├── TI_Edecay.cs
│ ├── TI_Ema.cs
│ ├── TI_Emv.cs
│ ├── TI_Exp.cs
│ ├── TI_Fisher.cs
│ ├── TI_Floor.cs
│ ├── TI_Fosc.cs
│ ├── TI_Hma.cs
│ ├── TI_Kama.cs
│ ├── TI_Kvo.cs
│ ├── TI_Lag.cs
│ ├── TI_LinReg.cs
│ ├── TI_LinRegIntercept.cs
│ ├── TI_LinRegSlope.cs
│ ├── TI_Ln.cs
│ ├── TI_Log10.cs
│ ├── TI_Macd.cs
│ ├── TI_MarketFi.cs
│ ├── TI_Mass.cs
│ ├── TI_Max.cs
│ ├── TI_Md.cs
│ ├── TI_MedPrice.cs
│ ├── TI_Mfi.cs
│ ├── TI_Min.cs
│ ├── TI_Mom.cs
│ ├── TI_Msw.cs
│ ├── TI_Mul.cs
│ ├── TI_Natr.cs
│ ├── TI_Nvi.cs
│ ├── TI_Obv.cs
│ ├── TI_Ppo.cs
│ ├── TI_Psar.cs
│ ├── TI_Pvi.cs
│ ├── TI_Qstick.cs
│ ├── TI_Roc.cs
│ ├── TI_RocR.cs
│ ├── TI_Round.cs
│ ├── TI_Rsi.cs
│ ├── TI_Sin.cs
│ ├── TI_Sinh.cs
│ ├── TI_Sma.cs
│ ├── TI_Sqrt.cs
│ ├── TI_StdDev.cs
│ ├── TI_StdErr.cs
│ ├── TI_Stoch.cs
│ ├── TI_StochRsi.cs
│ ├── TI_Sub.cs
│ ├── TI_Sum.cs
│ ├── TI_Tan.cs
│ ├── TI_Tanh.cs
│ ├── TI_Tema.cs
│ ├── TI_ToDeg.cs
│ ├── TI_ToRad.cs
│ ├── TI_Tr.cs
│ ├── TI_Trima.cs
│ ├── TI_Trix.cs
│ ├── TI_Trunc.cs
│ ├── TI_Tsf.cs
│ ├── TI_TypPrice.cs
│ ├── TI_UltOsc.cs
│ ├── TI_Var.cs
│ ├── TI_Vhf.cs
│ ├── TI_Vidya.cs
│ ├── TI_Volatility.cs
│ ├── TI_Vosc.cs
│ ├── TI_Vwma.cs
│ ├── TI_Wad.cs
│ ├── TI_WcPrice.cs
│ ├── TI_Wilders.cs
│ ├── TI_WillR.cs
│ ├── TI_Wma.cs
│ └── TI_ZlEma.cs
│ ├── Tinet.cs
│ └── Tulip.NETCore.csproj
├── tests
└── Tulip.NETCore.Tests
│ ├── AssemblyInfo.cs
│ ├── DataSets
│ ├── atoz.json
│ ├── extra.json
│ ├── testdata.schema.json
│ └── untest.json
│ ├── Indicator_Tests.cs
│ ├── JsonFileDataAttribute.cs
│ ├── Models
│ ├── JsonExtensions.cs
│ └── TestDataModel.cs
│ └── Tulip.NETCore.Tests.csproj
└── tulip.png
/.editorconfig:
--------------------------------------------------------------------------------
1 | root=true
2 |
3 | [*]
4 |
5 | #### Core EditorConfig Options ####
6 |
7 | # Indentation and spacing
8 | indent_style=space
9 | indent_size=2
10 | trim_trailing_whitespace=true
11 | charset=utf-8
12 | max_line_length=140
13 |
14 | # New line preferences
15 | insert_final_newline=true
16 |
17 | #### .NET Coding Conventions ####
18 |
19 | [*.cs]
20 |
21 | indent_size=4
22 |
23 | # Microsoft .NET properties
24 | dotnet_separate_import_directive_groups=false
25 | dotnet_sort_system_directives_first=true
26 | dotnet_style_predefined_type_for_locals_parameters_members=true:suggestion
27 | dotnet_style_predefined_type_for_member_access=false:suggestion
28 | csharp_new_line_before_open_brace=all
29 | csharp_new_line_before_else=true
30 | csharp_space_after_cast=true
31 | csharp_space_after_keywords_in_control_flow_statements=true
32 | dotnet_style_collection_initializer=true:suggestion
33 | dotnet_style_object_initializer=true:suggestion
34 | csharp_style_var_when_type_is_apparent=true:suggestion
35 | csharp_style_expression_bodied_methods=true:suggestion
36 | csharp_prefer_braces=true:warning
37 | # ReSharper properties
38 | resharper_place_accessorholder_attribute_on_same_line=false
39 | resharper_csharp_wrap_after_declaration_lpar=true
40 | resharper_csharp_wrap_parameters_style=chop_if_long
41 | resharper_max_formal_parameters_on_line=3
42 | resharper_blank_lines_around_single_line_auto_property=1
43 | resharper_csharp_keep_blank_lines_in_declarations=1
44 |
45 | #### XML Coding Conventions ####
46 |
47 | [*.xml]
48 | ij_xml_space_inside_empty_tag = true
49 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | buy_me_a_coffee: hmG3
2 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | name: .NET
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | build:
11 | strategy:
12 | matrix:
13 | operating-system: [ubuntu-latest, windows-latest, macOS-latest]
14 | runs-on: ${{ matrix.operating-system }}
15 | steps:
16 | - uses: actions/checkout@v4
17 | - uses: actions/setup-dotnet@v4
18 | with:
19 | dotnet-version: 8.0.x
20 | - name: Test & coverage
21 | run: dotnet test --logger "console;verbosity=normal" /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput=coverage/opencover-coverage.xml
22 | - name: Upload coverage to Codecov
23 | if: ${{ matrix.operating-system == 'ubuntu-latest' }}
24 | uses: codecov/codecov-action@v4
25 | with:
26 | name: codecov-tulip
27 | file: ./tests/Tulip.NETCore.Tests/coverage/opencover-coverage.xml
28 | token: ${{ secrets.CODECOV_TOKEN }}
29 | flags: unittests
30 | fail_ci_if_error: true
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.tlog
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
298 | *.vbp
299 |
300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
301 | *.dsw
302 | *.dsp
303 |
304 | # Visual Studio 6 technical files
305 | *.ncb
306 | *.aps
307 |
308 | # Visual Studio LightSwitch build output
309 | **/*.HTMLClient/GeneratedArtifacts
310 | **/*.DesktopClient/GeneratedArtifacts
311 | **/*.DesktopClient/ModelManifest.xml
312 | **/*.Server/GeneratedArtifacts
313 | **/*.Server/ModelManifest.xml
314 | _Pvt_Extensions
315 |
316 | # Paket dependency manager
317 | .paket/paket.exe
318 | paket-files/
319 |
320 | # FAKE - F# Make
321 | .fake/
322 |
323 | # CodeRush personal settings
324 | .cr/personal
325 |
326 | # Python Tools for Visual Studio (PTVS)
327 | __pycache__/
328 | *.pyc
329 |
330 | # Cake - Uncomment if you are using it
331 | # tools/**
332 | # !tools/packages.config
333 |
334 | # Tabs Studio
335 | *.tss
336 |
337 | # Telerik's JustMock configuration file
338 | *.jmconfig
339 |
340 | # BizTalk build output
341 | *.btp.cs
342 | *.btm.cs
343 | *.odx.cs
344 | *.xsd.cs
345 |
346 | # OpenCover UI analysis results
347 | OpenCover/
348 |
349 | # Azure Stream Analytics local run output
350 | ASALocalRun/
351 |
352 | # MSBuild Binary and Structured Log
353 | *.binlog
354 |
355 | # NVidia Nsight GPU debugger configuration file
356 | *.nvuser
357 |
358 | # MFractors (Xamarin productivity tool) working folder
359 | .mfractor/
360 |
361 | # Local History for Visual Studio
362 | .localhistory/
363 |
364 | # Visual Studio History (VSHistory) files
365 | .vshistory/
366 |
367 | # BeatPulse healthcheck temp database
368 | healthchecksdb
369 |
370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
371 | MigrationBackup/
372 |
373 | # Ionide (cross platform F# VS Code tools) working folder
374 | .ionide/
375 |
376 | # Fody - auto-generated XML schema
377 | FodyWeavers.xsd
378 |
379 | # VS Code files for those working on multiple tools
380 | .vscode/*
381 | !.vscode/settings.json
382 | !.vscode/tasks.json
383 | !.vscode/launch.json
384 | !.vscode/extensions.json
385 | *.code-workspace
386 |
387 | # Local History for Visual Studio Code
388 | .history/
389 |
390 | # Windows Installer files from build outputs
391 | *.cab
392 | *.msi
393 | *.msix
394 | *.msm
395 | *.msp
396 |
397 | # JetBrains Rider
398 | *.sln.iml
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Tulip Indicators for .NET Core
2 |
3 | Tulip.NETCore is an **unofficial** .NET port of the Tulip Indicators (TI) - open-source ANSI C library of functions for technical analysis of financial time series data. It is written entirely in C# for the .NET platform. This repository contains the source code of the latest version of the library released under GNU Lesser General Public License v3.0. This makes it free to use, even in commercial projects, with some restrictions.
4 |
5 | [](https://opensource.org/licenses/LGPL-3.0)
6 | [](https://nuget.org/packages/Tulip.NETCore)
7 | [](https://nuget.org/packages/Tulip.NETCore)
8 | [](https://github.com/hmG3/Tulip.NETCore/actions/workflows/dotnet.yml)
9 | [](https://codecov.io/gh/hmG3/Tulip.NETCore)
10 | [](https://app.codacy.com/gh/hmG3/Tulip.NETCore/dashboard)
11 |
12 | ## Supported frameworks
13 |
14 | - .NET 8
15 |
16 | ## Installation
17 |
18 | A compiled binary of Tulip.NETCore 0.8 is provided by the `Tulip.NETCore` NuGet package. To install it, run the following command in the Package Manager Console:
19 |
20 | ```shell
21 | Install-Package Tulip.NETCore
22 | ```
23 |
24 | or in .NET Core CLI:
25 |
26 | ```shell
27 | dotnet add package Tulip.NETCore
28 | ```
29 |
30 | ## Updates and bug fixes
31 |
32 | For more recent versions please refer to:
33 |
34 | - [Homepage of Tulip Indicators](https://tulipindicators.org/)
35 | - [Official GitHub repository](https://github.com/TulipCharts/tulipindicators)
36 |
--------------------------------------------------------------------------------
/Tulip.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.9.34607.119
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tulip.NETCore", "src\Tulip.NETCore\Tulip.NETCore.csproj", "{9E84826B-697A-42BD-BE10-3F5178D1CDDE}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tulip.NETCore.Tests", "tests\Tulip.NETCore.Tests\Tulip.NETCore.Tests.csproj", "{0FE7C705-C64D-4958-87EA-536B97389A33}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {9E84826B-697A-42BD-BE10-3F5178D1CDDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {9E84826B-697A-42BD-BE10-3F5178D1CDDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {9E84826B-697A-42BD-BE10-3F5178D1CDDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {9E84826B-697A-42BD-BE10-3F5178D1CDDE}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {0FE7C705-C64D-4958-87EA-536B97389A33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {0FE7C705-C64D-4958-87EA-536B97389A33}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {0FE7C705-C64D-4958-87EA-536B97389A33}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {0FE7C705-C64D-4958-87EA-536B97389A33}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {C7053D97-7D6D-4855-9800-3B803B6CBF8F}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/ArrayExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static class ArrayExtensions
4 | {
5 | public static void Deconstruct(this T[] array, out T first, out T second)
6 | {
7 | first = array[0];
8 | second = array[1];
9 | }
10 |
11 | public static void Deconstruct(this T[] array, out T first, out T second, out T third)
12 | {
13 | first = array[0];
14 | second = array[1];
15 | third = array[2];
16 | }
17 |
18 | public static void Deconstruct(this T[] array, out T first, out T second, out T third, out T fourth)
19 | {
20 | first = array[0];
21 | second = array[1];
22 | third = array[2];
23 | fourth = array[3];
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("Tulip.NETCore.Tests")]
4 | [assembly: InternalsVisibleTo("TaTooIne.Benchmark")]
5 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using System;
2 | global using System.Numerics;
3 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicator.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | public sealed class Indicator
4 | {
5 | internal Indicator(string name, string fullName, string inputs, string options, string outputs)
6 | {
7 | Name = name;
8 | FullName = fullName;
9 | Inputs = inputs.Split('|');
10 | Options = !String.IsNullOrEmpty(options) ? options.Split('|') : Array.Empty();
11 | Outputs = outputs.Split('|');
12 | }
13 |
14 | public string Name { get; }
15 |
16 | public string FullName { get; }
17 |
18 | public string[] Inputs { get; }
19 |
20 | public string[] Options { get; }
21 |
22 | public string[] Outputs { get; }
23 |
24 | public int Run(T[][] inputs, T[] options, T[][] outputs) where T : IFloatingPointIeee754 =>
25 | Tinet.IndicatorRun(Name, inputs, options, outputs);
26 |
27 | public int Start(T[] options) where T : IFloatingPointIeee754 => Tinet.IndicatorStart(Name, options);
28 |
29 | public override string ToString() => Name;
30 | }
31 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Abs.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int AbsStart(T[] options) => 0;
6 |
7 | private static int Abs(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Abs);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Acos.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int AcosStart(T[] options) => 0;
6 |
7 | private static int Acos(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Acos);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Ad.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int AdStart(T[] options) => 0;
6 |
7 | private static int Ad(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var (high, low, close, volume) = inputs;
10 | var output = outputs[0];
11 |
12 | T sum = T.Zero;
13 | for (var i = 0; i < size; ++i)
14 | {
15 | T hl = high[i] - low[i];
16 | if (!T.IsZero(hl))
17 | {
18 | sum += (close[i] - low[i] - high[i] + close[i]) / hl * volume[i];
19 | }
20 |
21 | output[i] = sum;
22 | }
23 |
24 | return TI_OKAY;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Add.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int AddStart(T[] options) => 0;
6 |
7 | private static int Add(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple2(size, inputs[0], inputs[1], outputs[0], (d1, d2) => d1 + d2);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Adosc.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int AdOscStart(T[] options) => Int32.CreateTruncating(options[1]) - 1;
6 |
7 | private static int AdOsc(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var shortPeriod = Int32.CreateTruncating(options[0]);
10 | var longPeriod = Int32.CreateTruncating(options[1]);
11 |
12 | if (shortPeriod < 1 || longPeriod < shortPeriod)
13 | {
14 | return TI_INVALID_OPTION;
15 | }
16 |
17 | if (size <= AdOscStart(options))
18 | {
19 | return TI_OKAY;
20 | }
21 |
22 | var (high, low, close, volume) = inputs;
23 | var output = outputs[0];
24 |
25 | int start = longPeriod - 1;
26 | T shortPer = TTwo / T.CreateChecked(shortPeriod + 1);
27 | T longPer = TTwo / T.CreateChecked(longPeriod + 1);
28 | T sum = T.Zero;
29 | T shortEma = T.Zero;
30 | T longEma = T.Zero;
31 | int outputIndex = default;
32 | for (var i = 0; i < size; ++i)
33 | {
34 | T hl = high[i] - low[i];
35 | if (!T.IsZero(hl))
36 | {
37 | sum += (close[i] - low[i] - high[i] + close[i]) / hl * volume[i];
38 | }
39 |
40 | if (i == 0)
41 | {
42 | shortEma = sum;
43 | longEma = sum;
44 | }
45 | else
46 | {
47 | shortEma = (sum - shortEma) * shortPer + shortEma;
48 | longEma = (sum - longEma) * longPer + longEma;
49 | }
50 |
51 | if (i >= start)
52 | {
53 | output[outputIndex++] = shortEma - longEma;
54 | }
55 | }
56 |
57 | return TI_OKAY;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Adx.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int AdxStart(T[] options) => (Int32.CreateTruncating(options[0]) - 1) * 2;
6 |
7 | private static int Adx(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 2)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= AdxStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low, close) = inputs;
22 | var output = outputs[0];
23 |
24 | T atr = T.Zero;
25 | T dmUp = T.Zero;
26 | T dmDown = T.Zero;
27 | for (var i = 1; i < period; ++i)
28 | {
29 | CalcTrueRange(low, high, close, i, out T trueRange);
30 | atr += trueRange;
31 |
32 | CalcDirection(high, low, i, out T dp, out T dm);
33 | dmUp += dp;
34 | dmDown += dm;
35 | }
36 |
37 | T per = T.CreateChecked(period - 1) / T.CreateChecked(period);
38 | T invPer = T.One / T.CreateChecked(period);
39 | T adx = T.Zero;
40 | T diUp = dmUp / atr;
41 | T diDown = dmDown / atr;
42 | T dx = T.Abs(diUp - diDown) / (diUp + diDown) * THundred;
43 | adx += dx;
44 |
45 | int outputIndex = default;
46 | for (var i = period; i < size; ++i)
47 | {
48 | CalcTrueRange(low, high, close, i, out T trueRange);
49 | atr = atr * per + trueRange;
50 |
51 | CalcDirection(high, low, i, out T dp, out T dm);
52 | dmUp = dmUp * per + dp;
53 | dmDown = dmDown * per + dm;
54 |
55 | diUp = dmUp / atr;
56 | diDown = dmDown / atr;
57 | dx = T.Abs(diUp - diDown) / (diUp + diDown) * THundred;
58 | if (i - period < period - 2)
59 | {
60 | adx += dx;
61 | }
62 | else if (i - period == period - 2)
63 | {
64 | adx += dx;
65 | output[outputIndex++] = adx * invPer;
66 | }
67 | else
68 | {
69 | adx = adx * per + dx;
70 | output[outputIndex++] = adx * invPer;
71 | }
72 | }
73 |
74 | return TI_OKAY;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Adxr.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int AdxrStart(T[] options) => (Int32.CreateTruncating(options[0]) - 1) * 3;
6 |
7 | private static int Adxr(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 2)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= AdxrStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low, close) = inputs;
22 | var output = outputs[0];
23 |
24 | T atr = T.Zero;
25 | T dmUp = T.Zero;
26 | T dmDown = T.Zero;
27 | for (var i = 1; i < period; ++i)
28 | {
29 | CalcTrueRange(low, high, close, i, out T trueRange);
30 | atr += trueRange;
31 |
32 | CalcDirection(high, low, i, out T dp, out T dm);
33 | dmUp += dp;
34 | dmDown += dm;
35 | }
36 |
37 | T per = T.CreateChecked(period - 1) / T.CreateChecked(period);
38 | T invPer = T.One / T.CreateChecked(period);
39 | T adx = T.Zero;
40 | T diUp = dmUp / atr;
41 | T diDown = dmDown / atr;
42 | T dx = T.Abs(diUp - diDown) / (diUp + diDown) * THundred;
43 | adx += dx;
44 |
45 | var adxr = BufferFactory(period - 1);
46 | int firstAdxr = AdxrStart(options);
47 |
48 | int outputIndex = default;
49 | for (var i = period; i < size; ++i)
50 | {
51 | CalcTrueRange(low, high, close, i, out T trueRange);
52 | atr = atr * per + trueRange;
53 |
54 | CalcDirection(high, low, i, out T dp, out T dm);
55 | dmUp = dmUp * per + dp;
56 | dmDown = dmDown * per + dm;
57 |
58 | diUp = dmUp / atr;
59 | diDown = dmDown / atr;
60 | dx = T.Abs(diUp - diDown) / (diUp + diDown) * THundred;
61 | if (i - period < period - 2)
62 | {
63 | adx += dx;
64 | }
65 | else if (i - period == period - 2)
66 | {
67 | adx += dx;
68 | BufferQPush(ref adxr, adx * invPer);
69 | }
70 | else
71 | {
72 | adx = adx * per + dx;
73 | if (i >= firstAdxr)
74 | {
75 | output[outputIndex++] = T.CreateChecked(0.5) * (adx * invPer + BufferGet(adxr, 1));
76 | }
77 |
78 | BufferQPush(ref adxr, adx * invPer);
79 | }
80 | }
81 |
82 | return TI_OKAY;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Ao.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int AoStart(T[] options) => 33;
6 |
7 | private static int Ao(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | if (size <= AoStart(options))
10 | {
11 | return TI_OKAY;
12 | }
13 |
14 | var (high, low) = inputs;
15 | var output = outputs[0];
16 |
17 | T sum34 = T.Zero;
18 | T sum5 = T.Zero;
19 | for (var i = 0; i < 34; ++i)
20 | {
21 | T hl = T.CreateChecked(0.5) * (high[i] + low[i]);
22 | sum34 += hl;
23 | if (i >= 29)
24 | {
25 | sum5 += hl;
26 | }
27 | }
28 |
29 | T per34 = T.One / T.CreateChecked(34);
30 | T per5 = T.One / T.CreateChecked(5);
31 | int outputIndex = default;
32 | output[outputIndex++] = per5 * sum5 - per34 * sum34;
33 | for (var i = 34; i < size; ++i)
34 | {
35 | T hl = T.CreateChecked(0.5) * (high[i] + low[i]);
36 | sum34 += hl;
37 | sum5 += hl;
38 |
39 | sum34 -= T.CreateChecked(0.5) * (high[i - 34] + low[i - 34]);
40 | sum5 -= T.CreateChecked(0.5) * (high[i - 5] + low[i - 5]);
41 | output[outputIndex++] = per5 * sum5 - per34 * sum34;
42 | }
43 |
44 | return TI_OKAY;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Apo.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int ApoStart(T[] options) => 1;
6 |
7 | private static int Apo(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var shortPeriod = Int32.CreateTruncating(options[0]);
10 | var longPeriod = Int32.CreateTruncating(options[1]);
11 |
12 | if (shortPeriod < 1 || longPeriod < 2 || longPeriod < shortPeriod)
13 | {
14 | return TI_INVALID_OPTION;
15 | }
16 |
17 | if (size <= ApoStart(options))
18 | {
19 | return TI_OKAY;
20 | }
21 |
22 | var input = inputs[0];
23 | var output = outputs[0];
24 |
25 | T shortPer = TTwo / T.CreateChecked(shortPeriod + 1);
26 | T longPer = TTwo / T.CreateChecked(longPeriod + 1);
27 | T shortEma = input[0];
28 | T longEma = input[0];
29 | int apoIndex = default;
30 | for (var i = 1; i < size; ++i)
31 | {
32 | shortEma = (input[i] - shortEma) * shortPer + shortEma;
33 | longEma = (input[i] - longEma) * longPer + longEma;
34 | output[apoIndex++] = shortEma - longEma;
35 | }
36 |
37 | return TI_OKAY;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Aroon.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int AroonStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int Aroon(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= AroonStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low) = inputs;
22 | var (aDown, aUp) = outputs;
23 |
24 | T scale = THundred / T.CreateChecked(period);
25 | var maxi = -1;
26 | var mini = -1;
27 | T max = high[0];
28 | T min = low[0];
29 |
30 | int aDownIndex = default;
31 | int aUpIndex = default;
32 | for (int i = period, trail = 0; i < size; ++i, ++trail)
33 | {
34 | // Maintain highest.
35 | T bar = high[i];
36 | int j;
37 | if (maxi < trail)
38 | {
39 | maxi = trail;
40 | max = high[maxi];
41 | j = trail;
42 | while (++j <= i)
43 | {
44 | bar = high[j];
45 | if (bar >= max)
46 | {
47 | max = bar;
48 | maxi = j;
49 | }
50 | }
51 | }
52 | else if (bar >= max)
53 | {
54 | maxi = i;
55 | max = bar;
56 | }
57 |
58 |
59 | // Maintain lowest.
60 | bar = low[i];
61 | if (mini < trail)
62 | {
63 | mini = trail;
64 | min = low[mini];
65 | j = trail;
66 | while (++j <= i)
67 | {
68 | bar = low[j];
69 | if (bar <= min)
70 | {
71 | min = bar;
72 | mini = j;
73 | }
74 | }
75 | }
76 | else if (bar <= min)
77 | {
78 | mini = i;
79 | min = bar;
80 | }
81 |
82 | // Calculate the indicator.
83 | aDown[aDownIndex++] = T.CreateChecked(period - (i - mini)) * scale;
84 | aUp[aUpIndex++] = T.CreateChecked(period - (i - maxi)) * scale;
85 | }
86 |
87 | return TI_OKAY;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_AroonOsc.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int AroonOscStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int AroonOsc(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= AroonStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low) = inputs;
22 | var output = outputs[0];
23 |
24 | T scale = THundred / T.CreateChecked(period);
25 | var maxi = -1;
26 | var mini = -1;
27 | T max = high[0];
28 | T min = low[0];
29 |
30 | int outputIndex = default;
31 | for (int i = period, trail = 0; i < size; ++i, ++trail)
32 | {
33 | // Maintain highest.
34 | T bar = high[i];
35 | int j;
36 | if (maxi < trail)
37 | {
38 | maxi = trail;
39 | max = high[maxi];
40 | j = trail;
41 | while (++j <= i)
42 | {
43 | bar = high[j];
44 | if (bar >= max)
45 | {
46 | max = bar;
47 | maxi = j;
48 | }
49 | }
50 | }
51 | else if (bar >= max)
52 | {
53 | maxi = i;
54 | max = bar;
55 | }
56 |
57 |
58 | // Maintain lowest.
59 | bar = low[i];
60 | if (mini < trail)
61 | {
62 | mini = trail;
63 | min = low[mini];
64 | j = trail;
65 | while (++j <= i)
66 | {
67 | bar = low[j];
68 | if (bar <= min)
69 | {
70 | min = bar;
71 | mini = j;
72 | }
73 | }
74 | }
75 | else if (bar <= min)
76 | {
77 | mini = i;
78 | min = bar;
79 | }
80 |
81 | output[outputIndex++] = T.CreateChecked(maxi - mini) * scale;
82 | }
83 |
84 | return TI_OKAY;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Asin.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int AsinStart(T[] options) => 0;
6 |
7 | private static int Asin(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Asin);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Atan.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int AtanStart(T[] options) => 0;
6 |
7 | private static int Atan(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Atan);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Atr.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int AtrStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Atr(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= AtrStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low, close) = inputs;
22 | var output = outputs[0];
23 |
24 | T sum = high[0] - low[0];
25 | for (var i = 1; i < period; ++i)
26 | {
27 | CalcTrueRange(low, high, close, i, out T trueRange);
28 | sum += trueRange;
29 | }
30 |
31 | T per = T.One / T.CreateChecked(period);
32 | T val = sum / T.CreateChecked(period);
33 | int outputIndex = default;
34 | output[outputIndex++] = val;
35 | for (var i = period; i < size; ++i)
36 | {
37 | CalcTrueRange(low, high, close, i, out T trueRange);
38 | val = (trueRange - val) * per + val;
39 | output[outputIndex++] = val;
40 | }
41 |
42 | return TI_OKAY;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_AvgPrice.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int AvgPriceStart(T[] options) => 0;
6 |
7 | private static int AvgPrice(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var (open, high, low, close) = inputs;
10 | var output = outputs[0];
11 |
12 | for (var i = 0; i < size; ++i)
13 | {
14 | output[i] = (open[i] + high[i] + low[i] + close[i]) * T.CreateChecked(0.25);
15 | }
16 |
17 | return TI_OKAY;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Bbands.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int BbandsStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Bbands(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 | var stddev = options[1];
11 |
12 | if (period < 1)
13 | {
14 | return TI_INVALID_OPTION;
15 | }
16 |
17 | if (size <= BbandsStart(options))
18 | {
19 | return TI_OKAY;
20 | }
21 |
22 | var input = inputs[0];
23 | var (lower, middle, upper) = outputs;
24 |
25 | T sum = T.Zero;
26 | T sum2 = T.Zero;
27 | for (var i = 0; i < period; ++i)
28 | {
29 | sum += input[i];
30 | sum2 += input[i] * input[i];
31 | }
32 |
33 | T scale = T.One / T.CreateChecked(period);
34 | T sd = T.Sqrt(sum2 * scale - sum * scale * (sum * scale));
35 |
36 | int lowerIndex = default;
37 | int middleIndex = default;
38 | int upperIndex = default;
39 | middle[middleIndex++] = sum * scale;
40 | lower[lowerIndex++] = middle[0] - stddev * sd;
41 | upper[upperIndex++] = middle[0] + stddev * sd;
42 | for (var i = period; i < size; ++i)
43 | {
44 | sum += input[i];
45 | sum2 += input[i] * input[i];
46 |
47 | sum -= input[i - period];
48 | sum2 -= input[i - period] * input[i - period];
49 |
50 | sd = T.Sqrt(sum2 * scale - sum * scale * (sum * scale));
51 | middle[middleIndex] = sum * scale;
52 | upper[upperIndex++] = middle[middleIndex] + stddev * sd;
53 | lower[lowerIndex++] = middle[middleIndex] - stddev * sd;
54 | ++middleIndex;
55 | }
56 |
57 | return TI_OKAY;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Bop.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int BopStart(T[] options) => 0;
6 |
7 | private static int Bop(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var (open, high, low, close) = inputs;
10 | var output = outputs[0];
11 |
12 | for (var i = 0; i < size; ++i)
13 | {
14 | T hl = high[i] - low[i];
15 | output[i] = hl > T.Zero ? (close[i] - open[i]) / hl : T.Zero;
16 | }
17 |
18 | return TI_OKAY;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Cci.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int CciStart(T[] options) => (Int32.CreateTruncating(options[0]) - 1) * 2;
6 |
7 | private static int Cci(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= CciStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low, close) = inputs;
22 | var output = outputs[0];
23 |
24 | T scale = T.One / T.CreateChecked(period);
25 | var sum = BufferFactory(period);
26 | int outputIndex = default;
27 | for (var i = 0; i < size; ++i)
28 | {
29 | T today = (high[i] + low[i] + close[i]) * (T.One / TThree);
30 | BufferPush(ref sum, today);
31 |
32 | T avg = sum.sum * scale;
33 | if (i >= period * 2 - 2)
34 | {
35 | T acc = T.Zero;
36 | for (var j = 0; j < period; ++j)
37 | {
38 | acc += T.Abs(avg - sum.vals[j]);
39 | }
40 |
41 | T cci = acc * scale * T.CreateChecked(0.015);
42 | cci = (today - avg) / cci;
43 | output[outputIndex++] = cci;
44 | }
45 | }
46 |
47 | return TI_OKAY;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Ceil.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int CeilStart(T[] options) => 0;
6 |
7 | private static int Ceil(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Ceiling);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Cmo.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int CmoStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int Cmo(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= CmoStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T upSum = T.Zero;
25 | T downSum = T.Zero;
26 | for (var i = 1; i <= period; ++i)
27 | {
28 | upSum += input[i] > input[i - 1] ? input[i] - input[i - 1] : T.Zero;
29 | downSum += input[i] < input[i - 1] ? input[i - 1] - input[i] : T.Zero;
30 | }
31 |
32 | int outputIndex = default;
33 | output[outputIndex++] = THundred * (upSum - downSum) / (upSum + downSum);
34 | for (var i = period + 1; i < size; ++i)
35 | {
36 | upSum -= input[i - period] > input[i - period - 1] ? input[i - period] - input[i - period - 1] : T.Zero;
37 | downSum -= input[i - period] < input[i - period - 1] ? input[i - period - 1] - input[i - period] : T.Zero;
38 |
39 | upSum += input[i] > input[i - 1] ? input[i] - input[i - 1] : T.Zero;
40 | downSum += input[i] < input[i - 1] ? input[i - 1] - input[i] : T.Zero;
41 |
42 | output[outputIndex++] = THundred * (upSum - downSum) / (upSum + downSum);
43 | }
44 |
45 | return TI_OKAY;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Cos.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int CosStart(T[] options) => 0;
6 |
7 | private static int Cos(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Cos);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Cosh.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int CoshStart(T[] options) => 0;
6 |
7 | private static int Cosh(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Cosh);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Crossany.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int CrossanyStart(T[] options) => 1;
6 |
7 | private static int Crossany(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var (a, b) = inputs;
10 | var output = outputs[0];
11 |
12 | int outputIndex = default;
13 | for (var i = 1; i < size; ++i)
14 | {
15 | output[outputIndex++] = a[i] > b[i] && a[i - 1] <= b[i - 1] || a[i] < b[i] && a[i - 1] >= b[i - 1] ? T.One : T.Zero;
16 | }
17 |
18 | return TI_OKAY;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Crossover.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int CrossoverStart(T[] options) => 1;
6 |
7 | private static int Crossover(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var (a, b) = inputs;
10 | var output = outputs[0];
11 |
12 | int outputIndex = default;
13 | for (var i = 1; i < size; ++i)
14 | {
15 | output[outputIndex++] = a[i] > b[i] && a[i - 1] <= b[i - 1] ? T.One : T.Zero;
16 | }
17 |
18 | return TI_OKAY;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Cvi.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int CviStart(T[] options) => Int32.CreateTruncating(options[0]) * 2 - 1;
6 |
7 | private static int Cvi(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= CviStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low) = inputs;
22 | var output = outputs[0];
23 |
24 | T per = TTwo / T.CreateChecked(period + 1);
25 | var lag = BufferFactory(period);
26 | T val = high[0] - low[0];
27 | for (var i = 1; i < period * 2 - 1; ++i)
28 | {
29 | val = (high[i] - low[i] - val) * per + val;
30 | BufferQPush(ref lag, val);
31 | }
32 |
33 | int outputIndex = default;
34 | for (var i = period * 2 - 1; i < size; ++i)
35 | {
36 | val = (high[i] - low[i] - val) * per + val;
37 | T old = lag.vals[lag.index];
38 | output[outputIndex++] = THundred * (val - old) / old;
39 | BufferQPush(ref lag, val);
40 | }
41 |
42 | return TI_OKAY;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Decay.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int DecayStart(T[] options) => 0;
6 |
7 | private static int Decay(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var input = inputs[0];
10 | var output = outputs[0];
11 | var period = Int32.CreateTruncating(options[0]);
12 |
13 | T scale = T.One / T.CreateChecked(period);
14 | int outputIndex = default;
15 | output[outputIndex++] = input[0];
16 | for (var i = 1; i < size; ++i)
17 | {
18 | T d = output[i - 1] - scale;
19 | output[outputIndex++] = input[i] > d ? input[i] : d;
20 | }
21 |
22 | return TI_OKAY;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Dema.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int DemaStart(T[] options) => (Int32.CreateTruncating(options[0]) - 1) * 2;
6 |
7 | private static int Dema(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= DemaStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T per = TTwo / T.CreateChecked(period + 1);
25 | T per1 = T.One - per;
26 |
27 | // Calculate EMA(input)
28 | T ema = input[0];
29 |
30 | // Calculate EMA(EMA(input))
31 | T ema2 = ema;
32 | int outputIndex = default;
33 | for (var i = 0; i < size; ++i)
34 | {
35 | ema = ema * per1 + input[i] * per;
36 | if (i == period - 1)
37 | {
38 | ema2 = ema;
39 | }
40 |
41 | if (i >= period - 1)
42 | {
43 | ema2 = ema2 * per1 + ema * per;
44 | if (i >= (period - 1) * 2)
45 | {
46 | output[outputIndex++] = ema * TTwo - ema2;
47 | }
48 | }
49 | }
50 |
51 | return TI_OKAY;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Di.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int DiStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Di(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= DiStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low, close) = inputs;
22 | var (plusDi, minusDi) = outputs;
23 |
24 | T atr = T.Zero;
25 | T dmUp = T.Zero;
26 | T dmDown = T.Zero;
27 | for (var i = 1; i < period; ++i)
28 | {
29 | CalcTrueRange(low, high, close, i, out T trueRange);
30 | atr += trueRange;
31 |
32 | CalcDirection(high, low, i, out T dp, out T dm);
33 | dmUp += dp;
34 | dmDown += dm;
35 | }
36 |
37 | T per = T.CreateChecked(period - 1) / T.CreateChecked(period);
38 | int plusDiIndex = default;
39 | int minusDiIndex = default;
40 | plusDi[plusDiIndex++] = THundred * dmUp / atr;
41 | minusDi[minusDiIndex++] = THundred * dmDown / atr;
42 | for (var i = period; i < size; ++i)
43 | {
44 | CalcTrueRange(low, high, close, i, out T trueRange);
45 | atr = atr * per + trueRange;
46 |
47 | CalcDirection(high, low, i, out T dp, out T dm);
48 | dmUp = dmUp * per + dp;
49 | dmDown = dmDown * per + dm;
50 |
51 | plusDi[plusDiIndex++] = THundred * dmUp / atr;
52 | minusDi[minusDiIndex++] = THundred * dmDown / atr;
53 | }
54 |
55 | return TI_OKAY;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Div.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int DivStart(T[] options) => 0;
6 |
7 | private static int Div(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple2(size, inputs[0], inputs[1], outputs[0], (d1, d2) => d1 / d2);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Dm.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int DmStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Dm(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= DmStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low) = inputs;
22 | var (plusDm, minusDm) = outputs;
23 |
24 | T dmUp = T.Zero;
25 | T dmDown = T.Zero;
26 | for (var i = 1; i < period; ++i)
27 | {
28 | CalcDirection(high, low, i, out T dp, out T dm);
29 |
30 | dmUp += dp;
31 | dmDown += dm;
32 | }
33 |
34 | T per = T.CreateChecked(period - 1) / T.CreateChecked(period);
35 | int plusDmIndex = default;
36 | int minusDmIndex = default;
37 | plusDm[plusDmIndex++] = dmUp;
38 | minusDm[minusDmIndex++] = dmDown;
39 | for (var i = period; i < size; ++i)
40 | {
41 | CalcDirection(high, low, i, out T dp, out T dm);
42 |
43 | dmUp = dmUp * per + dp;
44 | dmDown = dmDown * per + dm;
45 | plusDm[plusDmIndex++] = dmUp;
46 | minusDm[minusDmIndex++] = dmDown;
47 | }
48 |
49 | return TI_OKAY;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Dpo.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int DpoStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Dpo(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= DpoStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T sum = T.Zero;
25 | for (var i = 0; i < period; ++i)
26 | {
27 | sum += input[i];
28 | }
29 |
30 | T scale = T.One / T.CreateChecked(period);
31 | var back = period / 2 + 1;
32 | int outputIndex = default;
33 | output[outputIndex++] = input[period - 1 - back] - sum * scale;
34 | for (var i = period; i < size; ++i)
35 | {
36 | sum = sum + input[i] - input[i - period];
37 | output[outputIndex++] = input[i - back] - sum * scale;
38 | }
39 |
40 | return TI_OKAY;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Dx.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int DxStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Dx(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= DxStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low, close) = inputs;
22 | var output = outputs[0];
23 |
24 | T atr = T.Zero;
25 | T dmUp = T.Zero;
26 | T dmDown = T.Zero;
27 | for (var i = 1; i < period; ++i)
28 | {
29 | CalcTrueRange(low, high, close, i, out T trueRange);
30 | atr += trueRange;
31 |
32 | CalcDirection(high, low, i, out T dp, out T dm);
33 | dmUp += dp;
34 | dmDown += dm;
35 | }
36 |
37 | T per = T.CreateChecked(period - 1) / T.CreateChecked(period);
38 | T diUp = dmUp / atr;
39 | T diDown = dmDown / atr;
40 | T dx = T.Abs(diUp - diDown) / (diUp + diDown) * THundred;
41 | int outputIndex = default;
42 | output[outputIndex++] = dx;
43 | for (var i = period; i < size; ++i)
44 | {
45 | CalcTrueRange(low, high, close, i, out T trueRange);
46 | atr = atr * per + trueRange;
47 |
48 | CalcDirection(high, low, i, out T dp, out T dm);
49 | dmUp = dmUp * per + dp;
50 | dmDown = dmDown * per + dm;
51 |
52 | diUp = dmUp / atr;
53 | diDown = dmDown / atr;
54 | dx = T.Abs(diUp - diDown) / (diUp + diDown) * THundred;
55 | output[outputIndex++] = dx;
56 | }
57 |
58 | return TI_OKAY;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Edecay.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int EdecayStart(T[] options) => 0;
6 |
7 | private static int Edecay(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var input = inputs[0];
10 | var output = outputs[0];
11 | var period = Int32.CreateTruncating(options[0]);
12 |
13 | T scale = T.One - T.One / T.CreateChecked(period);
14 | int outputIndex = default;
15 | output[outputIndex++] = input[0];
16 | for (var i = 1; i < size; ++i)
17 | {
18 | T d = output[i - 1] * scale;
19 | output[outputIndex++] = input[i] > d ? input[i] : d;
20 | }
21 |
22 | return TI_OKAY;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Ema.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int EmaStart(T[] options) => 0;
6 |
7 | private static int Ema(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= EmaStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T per = TTwo / T.CreateChecked(period + 1);
25 | T val = input[0];
26 | int outputIndex = default;
27 | output[outputIndex++] = val;
28 | for (var i = 1; i < size; ++i)
29 | {
30 | val = (input[i] - val) * per + val;
31 | output[outputIndex++] = val;
32 | }
33 |
34 | return TI_OKAY;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Emv.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int EmvStart(T[] options) => 1;
6 |
7 | private static int Emv(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | if (size <= EmvStart(options))
10 | {
11 | return TI_OKAY;
12 | }
13 |
14 | var (high, low, volume) = inputs;
15 | var output = outputs[0];
16 |
17 | T last = (high[0] + low[0]) * T.CreateChecked(0.5);
18 | int outputIndex = default;
19 | for (var i = 1; i < size; ++i)
20 | {
21 | T hl = (high[i] + low[i]) * T.CreateChecked(0.5);
22 | T br = volume[i] / T.CreateChecked(10000) / (high[i] - low[i]);
23 | output[outputIndex++] = (hl - last) / br;
24 | last = hl;
25 | }
26 |
27 | return TI_OKAY;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Exp.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int ExpStart(T[] options) => 0;
6 |
7 | private static int Exp(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Exp);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Fisher.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int FisherStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Fisher(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= FisherStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low) = inputs;
22 | var (fisher, signal) = outputs;
23 |
24 | var maxi = -1;
25 | var mini = -1;
26 | var THalf = T.CreateChecked(0.5);
27 | T max = THalf * (high[0] + low[0]);
28 | T min = THalf * (high[0] + low[0]);
29 | T val1 = T.Zero;
30 | T fish = T.Zero;
31 | int fisherIndex = default;
32 | int signalIndex = default;
33 | for (int i = period - 1, trail = 0; i < size; ++i, ++trail)
34 | {
35 | // Maintain highest.
36 | T bar = THalf * (high[i] + low[i]);
37 | if (maxi < trail)
38 | {
39 | maxi = trail;
40 | max = THalf * (high[maxi] + low[maxi]);
41 | int j = trail;
42 | while (++j <= i)
43 | {
44 | bar = THalf * (high[j] + low[j]);
45 | if (bar >= max)
46 | {
47 | max = bar;
48 | maxi = j;
49 | }
50 | }
51 | }
52 | else if (bar >= max)
53 | {
54 | maxi = i;
55 | max = bar;
56 | }
57 |
58 | // Maintain lowest.
59 | bar = THalf * (high[i] + low[i]);
60 | if (mini < trail)
61 | {
62 | mini = trail;
63 | min = THalf * (high[mini] + low[mini]);
64 | int j = trail;
65 | while (++j <= i)
66 | {
67 | bar = THalf * (high[j] + low[j]);
68 | if (bar <= min)
69 | {
70 | min = bar;
71 | mini = j;
72 | }
73 | }
74 | }
75 | else if (bar <= min)
76 | {
77 | mini = i;
78 | min = bar;
79 | }
80 |
81 | T mm = max - min;
82 | if (T.IsZero(mm))
83 | {
84 | mm = T.CreateChecked(0.001);
85 | }
86 |
87 | val1 = T.CreateChecked(0.66) * ((THalf * (high[i] + low[i]) - min) / mm - THalf) + T.CreateChecked(0.67) * val1;
88 | if (val1 > T.CreateChecked(0.99))
89 | {
90 | val1 = T.CreateChecked(0.999);
91 | }
92 |
93 | if (val1 < T.CreateChecked(-0.99))
94 | {
95 | val1 = T.CreateChecked(-0.999);
96 | }
97 |
98 | signal[signalIndex++] = fish;
99 | fish = THalf * T.Log((T.One + val1) / (T.One - val1)) + THalf * fish;
100 | fisher[fisherIndex++] = fish;
101 | }
102 |
103 | return TI_OKAY;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Floor.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int FloorStart(T[] options) => 0;
6 |
7 | private static int Floor(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Floor);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Fosc.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int FoscStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int Fosc(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= FoscStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T x = T.Zero; // Sum of Xs.
25 | T x2 = T.Zero; // Sum of square of Xs.
26 | T y = T.Zero; // Flat sum of previous numbers.
27 | T xy = T.Zero; // Weighted sum of previous numbers.
28 | T tsf = T.Zero;
29 | for (var i = 0; i < period - 1; ++i)
30 | {
31 | x += T.CreateChecked(i + 1);
32 | x2 += T.CreateChecked((i + 1) * (i + 1));
33 | xy += input[i] * T.CreateChecked(i + 1);
34 | y += input[i];
35 | }
36 |
37 | x += T.CreateChecked(period);
38 | x2 += T.CreateChecked(period * period);
39 |
40 | T p = T.One / T.CreateChecked(period);
41 | T bd = T.One / (T.CreateChecked(period) * x2 - x * x);
42 | int outputIndex = default;
43 | for (var i = period - 1; i < size; ++i)
44 | {
45 | xy += input[i] * T.CreateChecked(period);
46 | y += input[i];
47 | T b = (T.CreateChecked(period) * xy - x * y) * bd;
48 | T a = (y - b * x) * p;
49 | if (i >= period)
50 | {
51 | output[outputIndex++] = THundred * (input[i] - tsf) / input[i];
52 | }
53 |
54 | tsf = a + b * T.CreateChecked(period + 1);
55 | xy -= y;
56 | y -= input[i - period + 1];
57 | }
58 |
59 | return TI_OKAY;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Hma.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int HmaStart(T[] options)
6 | {
7 | var period = Int32.CreateTruncating(options[0]);
8 | return period + Int32.CreateTruncating(T.Sqrt(T.CreateChecked(period))) - 2;
9 | }
10 |
11 | private static int Hma(int size, T[][] inputs, T[] options, T[][] outputs)
12 | {
13 | var period = Int32.CreateTruncating(options[0]);
14 |
15 | if (period < 1)
16 | {
17 | return TI_INVALID_OPTION;
18 | }
19 |
20 | if (size <= HmaStart(options))
21 | {
22 | return TI_OKAY;
23 | }
24 |
25 | var input = inputs[0];
26 | var output = outputs[0];
27 |
28 | // HMA(input, N) = WMA((2 * WMA(input, N/2) - WMA(input, N)), sqrt(N))
29 | // Need to do three WMAs, with periods N, N/2, and sqrt N.
30 |
31 | var period2 = period / 2;
32 | T sum = T.Zero; // Flat sum of previous numbers.
33 | T weightSum = T.Zero; // Weighted sum of previous numbers.
34 | T sum2 = T.Zero;
35 | T weightSum2 = T.Zero;
36 | // Setup up the WMA(period) and WMA(period/2) on the input.
37 | for (var i = 0; i < period - 1; ++i)
38 | {
39 | weightSum += input[i] * T.CreateChecked(i + 1);
40 | sum += input[i];
41 | if (i >= period - period2)
42 | {
43 | weightSum2 += input[i] * T.CreateChecked(i + 1 - (period - period2));
44 | sum2 += input[i];
45 | }
46 | }
47 |
48 | var periodSqrt = Int32.CreateTruncating(T.Sqrt(T.CreateChecked(period)));
49 | T weights = T.CreateChecked(period * (period + 1)) / TTwo;
50 | T weights2 = T.CreateChecked(period2 * (period2 + 1)) / TTwo;
51 | T weightsSqrt = T.CreateChecked(periodSqrt * (periodSqrt + 1)) / TTwo;
52 | T sumSqrt = T.Zero;
53 | T weightSumSqrt = T.Zero;
54 | var buff = BufferFactory(periodSqrt);
55 | int outputIndex = default;
56 | for (var i = period - 1; i < size; ++i)
57 | {
58 | weightSum += input[i] * T.CreateChecked(period);
59 | sum += input[i];
60 |
61 | weightSum2 += input[i] * T.CreateChecked(period2);
62 | sum2 += input[i];
63 |
64 | T wma = weightSum / weights;
65 | T wma2 = weightSum2 / weights2;
66 | T diff = TTwo * wma2 - wma;
67 |
68 | weightSumSqrt += diff * T.CreateChecked(periodSqrt);
69 | sumSqrt += diff;
70 | BufferQPush(ref buff, diff);
71 |
72 | if (i >= period - 1 + (periodSqrt - 1))
73 | {
74 | output[outputIndex++] = weightSumSqrt / weightsSqrt;
75 |
76 | weightSumSqrt -= sumSqrt;
77 | sumSqrt -= BufferGet(buff, 1);
78 | }
79 | else
80 | {
81 | weightSumSqrt -= sumSqrt;
82 | }
83 |
84 |
85 | weightSum -= sum;
86 | sum -= input[i - period + 1];
87 |
88 | weightSum2 -= sum2;
89 | sum2 -= input[i - period2 + 1];
90 | }
91 |
92 | return TI_OKAY;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Kama.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int KamaStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Kama(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= KamaStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T sum = T.Zero;
25 | for (var i = 1; i < period; ++i)
26 | {
27 | sum += T.Abs(input[i] - input[i - 1]);
28 | }
29 |
30 | // The caller selects the period used in the efficiency ratio. The fast and slow periods are hard set by the algorithm.
31 | T shortPer = TTwo / T.CreateChecked(2 + 1);
32 | T longPer = TTwo / T.CreateChecked(30 + 1);
33 |
34 | T kama = input[period - 1];
35 | int outputIndex = default;
36 | output[outputIndex++] = kama;
37 | for (var i = period; i < size; ++i)
38 | {
39 | sum += T.Abs(input[i] - input[i - 1]);
40 | if (i > period)
41 | {
42 | sum -= T.Abs(input[i - period] - input[i - period - 1]);
43 | }
44 |
45 | T er = !T.IsZero(sum) ? T.Abs(input[i] - input[i - period]) / sum : T.One;
46 | T sc = T.Pow(er * (shortPer - longPer) + longPer, TTwo);
47 |
48 | kama += sc * (input[i] - kama);
49 | output[outputIndex++] = kama;
50 | }
51 |
52 | return TI_OKAY;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Kvo.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int KvoStart(T[] options) => 1;
6 |
7 | private static int Kvo(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var shortPeriod = Int32.CreateTruncating(options[0]);
10 | var longPeriod = Int32.CreateTruncating(options[1]);
11 |
12 | if (shortPeriod < 1 || longPeriod < shortPeriod)
13 | {
14 | return TI_INVALID_OPTION;
15 | }
16 |
17 | if (size <= KvoStart(options))
18 | {
19 | return TI_OKAY;
20 | }
21 |
22 | var (high, low, close, volume) = inputs;
23 | var output = outputs[0];
24 |
25 | T shortPer = TTwo / T.CreateChecked(shortPeriod + 1);
26 | T longPer = TTwo / T.CreateChecked(longPeriod + 1);
27 | T cm = T.Zero;
28 | T prevHlc = high[0] + low[0] + close[0];
29 | var trend = -1;
30 | T shortEma = T.Zero;
31 | T longEma = T.Zero;
32 | int outputIndex = default;
33 | for (var i = 1; i < size; ++i)
34 | {
35 | T hlc = high[i] + low[i] + close[i];
36 | T dm = high[i] - low[i];
37 | if (hlc > prevHlc && trend != 1)
38 | {
39 | trend = 1;
40 | cm = high[i - 1] - low[i - 1];
41 | }
42 | else if (hlc < prevHlc && trend != 0)
43 | {
44 | trend = 0;
45 | cm = high[i - 1] - low[i - 1];
46 | }
47 |
48 | cm += dm;
49 | T vf = volume[i] * T.Abs(dm / cm * TTwo - T.One) * THundred * (trend == 0 ? T.NegativeOne : T.One);
50 | if (i == 1)
51 | {
52 | shortEma = vf;
53 | longEma = vf;
54 | }
55 | else
56 | {
57 | shortEma = (vf - shortEma) * shortPer + shortEma;
58 | longEma = (vf - longEma) * longPer + longEma;
59 | }
60 |
61 | output[outputIndex++] = shortEma - longEma;
62 | prevHlc = hlc;
63 | }
64 |
65 | return TI_OKAY;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Lag.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int LagStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int Lag(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 0)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= LagStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | int outputIndex = default;
25 | for (var i = period; i < size; ++i)
26 | {
27 | output[outputIndex++] = input[i - period];
28 | }
29 |
30 | return TI_OKAY;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_LinReg.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int LinRegStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int LinReg(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= LinRegStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T x = T.Zero; // Sum of Xs.
25 | T x2 = T.Zero; // Sum of square of Xs.
26 | T y = T.Zero; // Flat sum of previous numbers.
27 | T xy = T.Zero; // Weighted sum of previous numbers.
28 | for (var i = 0; i < period - 1; ++i)
29 | {
30 | x += T.CreateChecked(i + 1);
31 | x2 += T.CreateChecked((i + 1) * (i + 1));
32 | xy += input[i] * T.CreateChecked(i + 1);
33 | y += input[i];
34 | }
35 |
36 | x += T.CreateChecked(period);
37 | x2 += T.CreateChecked(period * period);
38 |
39 | T p = T.One / T.CreateChecked(period);
40 | T bd = T.One / (T.CreateChecked(period) * x2 - x * x);
41 | int outputIndex = default;
42 | for (var i = period - 1; i < size; ++i)
43 | {
44 | xy += input[i] * T.CreateChecked(period);
45 | y += input[i];
46 | T b = (T.CreateChecked(period) * xy - x * y) * bd;
47 | T a = (y - b * x) * p;
48 | output[outputIndex++] = a + b * T.CreateChecked(period);
49 | xy -= y;
50 | y -= input[i - period + 1];
51 | }
52 |
53 | return TI_OKAY;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_LinRegIntercept.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int LinRegInterceptStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int LinRegIntercept(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= LinRegStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T x = T.Zero; // Sum of Xs.
25 | T x2 = T.Zero; // Sum of square of Xs.
26 | T y = T.Zero; // Flat sum of previous numbers.
27 | T xy = T.Zero; // Weighted sum of previous numbers.
28 | for (var i = 0; i < period - 1; ++i)
29 | {
30 | x += T.CreateChecked(i + 1);
31 | x2 += T.CreateChecked((i + 1) * (i + 1));
32 | xy += input[i] * T.CreateChecked(i + 1);
33 | y += input[i];
34 | }
35 |
36 | x += T.CreateChecked(period);
37 | x2 += T.CreateChecked(period * period);
38 |
39 | T p = T.One / T.CreateChecked(period);
40 | T bd = T.One / (T.CreateChecked(period) * x2 - x * x);
41 | int outputIndex = default;
42 | for (var i = period - 1; i < size; ++i)
43 | {
44 | xy += input[i] * T.CreateChecked(period);
45 | y += input[i];
46 | T b = (T.CreateChecked(period) * xy - x * y) * bd;
47 | T a = (y - b * x) * p;
48 | output[outputIndex++] = a + b;
49 | xy -= y;
50 | y -= input[i - period + 1];
51 | }
52 |
53 | return TI_OKAY;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_LinRegSlope.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int LinRegSlopeStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int LinRegSlope(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= LinRegStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T x = T.Zero; // Sum of Xs.
25 | T x2 = T.Zero; // Sum of square of Xs.
26 | T y = T.Zero; // Flat sum of previous numbers.
27 | T xy = T.Zero; // Weighted sum of previous numbers.
28 | for (var i = 0; i < period - 1; ++i)
29 | {
30 | x += T.CreateChecked(i + 1);
31 | x2 += T.CreateChecked((i + 1) * (i + 1));
32 | xy += input[i] * T.CreateChecked(i + 1);
33 | y += input[i];
34 | }
35 |
36 | x += T.CreateChecked(period);
37 | x2 += T.CreateChecked(period * period);
38 |
39 | T bd = T.One / (T.CreateChecked(period) * x2 - x * x);
40 | int outputIndex = default;
41 | for (var i = period - 1; i < size; ++i)
42 | {
43 | xy += input[i] * T.CreateChecked(period);
44 | y += input[i];
45 | T b = (T.CreateChecked(period) * xy - x * y) * bd;
46 | output[outputIndex++] = b;
47 | xy -= y;
48 | y -= input[i - period + 1];
49 | }
50 |
51 | return TI_OKAY;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Ln.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int LnStart(T[] options) => 0;
6 |
7 | private static int Ln(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Log);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Log10.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int Log10Start(T[] options) => 0;
6 |
7 | private static int Log10(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Log10);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Macd.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int MacdStart(T[] options)
6 | {
7 | // NB we return data before signal is strictly valid.
8 | int longPeriod = Int32.CreateTruncating(options[1]);
9 | return longPeriod - 1;
10 | }
11 |
12 | private static int Macd(int size, T[][] inputs, T[] options, T[][] outputs)
13 | {
14 | var shortPeriod = Int32.CreateTruncating(options[0]);
15 | var longPeriod = Int32.CreateTruncating(options[1]);
16 | var signalPeriod = Int32.CreateTruncating(options[2]);
17 |
18 | if (shortPeriod < 1 || longPeriod < 2 || longPeriod < shortPeriod || signalPeriod < 1)
19 | {
20 | return TI_INVALID_OPTION;
21 | }
22 |
23 | if (size <= MacdStart(options))
24 | {
25 | return TI_OKAY;
26 | }
27 |
28 | var input = inputs[0];
29 | var (macd, signal, hist) = outputs;
30 |
31 | T shortPer = TTwo / T.CreateChecked(shortPeriod + 1);
32 | T longPer = TTwo / T.CreateChecked(longPeriod + 1);
33 | if (shortPeriod == 12 && longPeriod == 26)
34 | {
35 | // It's what people expect.
36 | shortPer = T.CreateChecked(0.15);
37 | longPer = T.CreateChecked(0.075);
38 | }
39 |
40 | T signalPer = TTwo / T.CreateChecked(signalPeriod + 1);
41 | T shortEma = input[0];
42 | T longEma = input[0];
43 | T signalEma = T.Zero;
44 | int macdIndex = default;
45 | int signalIndex = default;
46 | int histIndex = default;
47 | for (var i = 1; i < size; ++i)
48 | {
49 | shortEma = (input[i] - shortEma) * shortPer + shortEma;
50 | longEma = (input[i] - longEma) * longPer + longEma;
51 | T outEma = shortEma - longEma;
52 | if (i == longPeriod - 1)
53 | {
54 | signalEma = outEma;
55 | }
56 |
57 | if (i >= longPeriod - 1)
58 | {
59 | signalEma = (outEma - signalEma) * signalPer + signalEma;
60 | macd[macdIndex++] = outEma;
61 | signal[signalIndex++] = signalEma;
62 | hist[histIndex++] = outEma - signalEma;
63 | }
64 | }
65 |
66 | return TI_OKAY;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_MarketFi.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int MarketFiStart(T[] options) => 0;
6 |
7 | private static int MarketFi(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | if (size <= MarketFiStart(options))
10 | {
11 | return TI_OKAY;
12 | }
13 |
14 | var (high, low, volume) = inputs;
15 | var output = outputs[0];
16 |
17 | int outputIndex = default;
18 | for (var i = 0; i < size; ++i)
19 | {
20 | output[outputIndex++] = (high[i] - low[i]) / volume[i];
21 | }
22 |
23 | return TI_OKAY;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Mass.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int MassStart(T[] options)
6 | {
7 | var sumP = Int32.CreateTruncating(options[0]) - 1;
8 | // The ema uses a hard-coded period of 9. (9-1)*2 = 16
9 | return 16 + sumP;
10 | }
11 |
12 | private static int Mass(int size, T[][] inputs, T[] options, T[][] outputs)
13 | {
14 | var period = Int32.CreateTruncating(options[0]);
15 |
16 | if (period < 1)
17 | {
18 | return TI_INVALID_OPTION;
19 | }
20 |
21 | if (size <= MassStart(options))
22 | {
23 | return TI_OKAY;
24 | }
25 |
26 | var (high, low) = inputs;
27 | var output = outputs[0];
28 |
29 | // mass uses a hard-coded 9 period for the ema
30 | T per = TTwo / T.CreateChecked(9 + 1);
31 | T per1 = T.One - per;
32 |
33 | // Calculate EMA(h-l)
34 | T ema = high[0] - low[0];
35 |
36 | // Calculate EMA(EMA(h-l))
37 | T ema2 = ema;
38 | var sum = BufferFactory(period);
39 | int outputIndex = default;
40 | for (var i = 0; i < size; ++i)
41 | {
42 | T hl = high[i] - low[i];
43 | ema = ema * per1 + hl * per;
44 | if (i == 8)
45 | {
46 | ema2 = ema;
47 | }
48 |
49 | if (i < 8)
50 | {
51 | continue;
52 | }
53 |
54 | ema2 = ema2 * per1 + ema * per;
55 | if (i >= 16)
56 | {
57 | BufferPush(ref sum, ema / ema2);
58 |
59 | if (i >= period + 16 - 1)
60 | {
61 | output[outputIndex++] = sum.sum;
62 | }
63 | }
64 | }
65 |
66 | return TI_OKAY;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Max.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int MaxStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Max(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= MaxStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | var maxi = -1;
25 | T max = input[0];
26 | int outputIndex = default;
27 | for (int i = period - 1, trail = 0; i < size; ++i, ++trail)
28 | {
29 | T bar = input[i];
30 |
31 | if (maxi < trail)
32 | {
33 | maxi = trail;
34 | max = input[maxi];
35 | int j = trail;
36 | while (++j <= i)
37 | {
38 | bar = input[j];
39 | if (bar >= max)
40 | {
41 | max = bar;
42 | maxi = j;
43 | }
44 | }
45 | }
46 | else if (bar >= max)
47 | {
48 | maxi = i;
49 | max = bar;
50 | }
51 |
52 | output[outputIndex++] = max;
53 | }
54 |
55 | return TI_OKAY;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Md.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int MdStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Md(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= MdStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T scale = T.One / T.CreateChecked(period);
25 | T sum = T.Zero;
26 | int outputIndex = default;
27 | for (var i = 0; i < size; ++i)
28 | {
29 | T today = input[i];
30 | sum += today;
31 | if (i >= period)
32 | {
33 | sum -= input[i - period];
34 | }
35 |
36 | T avg = sum * scale;
37 | if (i >= period - 1)
38 | {
39 | T acc = T.Zero;
40 | for (var j = 0; j < period; ++j)
41 | {
42 | acc += T.Abs(avg - input[i - j]);
43 | }
44 |
45 | output[outputIndex++] = acc * scale;
46 | }
47 | }
48 |
49 | return TI_OKAY;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_MedPrice.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int MedPriceStart(T[] options) => 0;
6 |
7 | private static int MedPrice(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var (high, low) = inputs;
10 | var output = outputs[0];
11 |
12 | for (var i = 0; i < size; ++i)
13 | {
14 | output[i] = (high[i] + low[i]) * T.CreateChecked(0.5);
15 | }
16 |
17 | return TI_OKAY;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Mfi.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int MfiStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int Mfi(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= MfiStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low, close, volume) = inputs;
22 | var output = outputs[0];
23 |
24 | T yTyp = (high[0] + low[0] + close[0]) * (T.One / TThree);
25 | var up = BufferFactory(period);
26 | var down = BufferFactory(period);
27 | int outputIndex = default;
28 | for (var i = 1; i < size; ++i)
29 | {
30 | T typ = (high[i] + low[i] + close[i]) * (T.One / TThree);
31 | T bar = typ * volume[i];
32 | if (typ > yTyp)
33 | {
34 | BufferPush(ref up, bar);
35 | BufferPush(ref down, T.Zero);
36 | }
37 | else if (typ < yTyp)
38 | {
39 | BufferPush(ref down, bar);
40 | BufferPush(ref up, T.Zero);
41 | }
42 | else
43 | {
44 | BufferPush(ref up, T.Zero);
45 | BufferPush(ref down, T.Zero);
46 | }
47 |
48 | yTyp = typ;
49 | if (i >= period)
50 | {
51 | output[outputIndex++] = up.sum / (up.sum + down.sum) * THundred;
52 | }
53 | }
54 |
55 | return TI_OKAY;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Min.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int MinStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Min(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= MinStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | var mini = -1;
25 | T min = input[0];
26 | int outputIndex = default;
27 | for (int i = period - 1, trail = 0; i < size; ++i, ++trail)
28 | {
29 | T bar = input[i];
30 | if (mini < trail)
31 | {
32 | mini = trail;
33 | min = input[mini];
34 | int j = trail;
35 | while (++j <= i)
36 | {
37 | bar = input[j];
38 | if (bar <= min)
39 | {
40 | min = bar;
41 | mini = j;
42 | }
43 | }
44 | }
45 | else if (bar <= min)
46 | {
47 | mini = i;
48 | min = bar;
49 | }
50 |
51 | output[outputIndex++] = min;
52 | }
53 |
54 | return TI_OKAY;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Mom.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int MomStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int Mom(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= MomStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | int outputIndex = default;
25 | for (var i = period; i < size; ++i)
26 | {
27 | output[outputIndex++] = input[i] - input[i - period];
28 | }
29 |
30 | return TI_OKAY;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Msw.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int MswStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int Msw(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= MswStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var (sine, lead) = outputs;
23 |
24 | T tpi = TTwo * T.Pi;
25 | int sineIndex = default;
26 | int leadIndex = default;
27 | for (var i = period; i < size; ++i)
28 | {
29 | T rp = T.Zero;
30 | T ip = T.Zero;
31 | for (var j = 0; j < period; ++j)
32 | {
33 | T weight = input[i - j];
34 | rp += T.Cos(tpi * T.CreateChecked(j) / T.CreateChecked(period)) * weight;
35 | ip += T.Sin(tpi * T.CreateChecked(j) / T.CreateChecked(period)) * weight;
36 | }
37 |
38 | T phase;
39 | if (T.Abs(rp) > T.CreateChecked(0.001))
40 | {
41 | phase = T.Atan(ip / rp);
42 | }
43 | else
44 | {
45 | phase = tpi / TTwo * (ip < T.Zero ? T.NegativeZero : T.Zero);
46 | }
47 |
48 | if (rp < T.Zero)
49 | {
50 | phase += T.Pi;
51 | }
52 |
53 | phase += T.Pi / TTwo;
54 | if (phase < T.Zero)
55 | {
56 | phase += tpi;
57 | }
58 |
59 | if (phase > tpi)
60 | {
61 | phase -= tpi;
62 | }
63 |
64 | sine[sineIndex++] = T.Sin(phase);
65 | lead[leadIndex++] = T.Sin(phase + T.Pi / T.CreateChecked(4));
66 | }
67 |
68 | return TI_OKAY;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Mul.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int MulStart(T[] options) => 0;
6 |
7 | private static int Mul(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple2(size, inputs[0], inputs[1], outputs[0], (d1, d2) => d1 * d2);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Natr.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int NatrStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Natr(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= NatrStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low, close) = inputs;
22 | var output = outputs[0];
23 |
24 | T sum = high[0] - low[0];
25 | int outputIndex = default;
26 | for (var i = 1; i < period; ++i)
27 | {
28 | CalcTrueRange(low, high, close, i, out T trueRange);
29 | sum += trueRange;
30 | }
31 |
32 | T per = T.One / T.CreateChecked(period);
33 | T val = sum / T.CreateChecked(period);
34 | output[outputIndex++] = THundred * val / close[period - 1];
35 | for (var i = period; i < size; ++i)
36 | {
37 | CalcTrueRange(low, high, close, i, out T trueRange);
38 | val = (trueRange - val) * per + val;
39 | output[outputIndex++] = THundred * val / close[i];
40 | }
41 |
42 | return TI_OKAY;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Nvi.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int NviStart(T[] options) => 0;
6 |
7 | private static int Nvi(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | if (size <= NviStart(options))
10 | {
11 | return TI_OKAY;
12 | }
13 |
14 | var (close, volume) = inputs;
15 | var output = outputs[0];
16 |
17 | T nvi = T.CreateChecked(1000);
18 | int outputIndex = default;
19 | output[outputIndex++] = nvi;
20 | for (var i = 1; i < size; ++i)
21 | {
22 | if (volume[i] < volume[i - 1])
23 | {
24 | nvi += (close[i] - close[i - 1]) / close[i - 1] * nvi;
25 | }
26 |
27 | output[outputIndex++] = nvi;
28 | }
29 |
30 | return TI_OKAY;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Obv.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int ObvStart(T[] options) => 0;
6 |
7 | private static int Obv(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var (close, volume) = inputs;
10 | var output = outputs[0];
11 |
12 | T prev = close[0];
13 | T sum = T.Zero;
14 | int outputIndex = default;
15 | output[outputIndex++] = sum;
16 | for (var i = 1; i < size; ++i)
17 | {
18 | if (close[i] > prev)
19 | {
20 | sum += volume[i];
21 | }
22 | else if (close[i] < prev)
23 | {
24 | sum -= volume[i];
25 | }
26 |
27 | prev = close[i];
28 | output[outputIndex++] = sum;
29 | }
30 |
31 | return TI_OKAY;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Ppo.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int PpoStart(T[] options) => 1;
6 |
7 | private static int Ppo(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var shortPeriod = Int32.CreateTruncating(options[0]);
10 | var longPeriod = Int32.CreateTruncating(options[1]);
11 |
12 | if (shortPeriod < 1 || longPeriod < 2 || longPeriod < shortPeriod)
13 | {
14 | return TI_INVALID_OPTION;
15 | }
16 |
17 | if (size <= PpoStart(options))
18 | {
19 | return TI_OKAY;
20 | }
21 |
22 | var input = inputs[0];
23 | var output = outputs[0];
24 |
25 | T shortPer = TTwo / T.CreateChecked(shortPeriod + 1);
26 | T longPer = TTwo / T.CreateChecked(longPeriod + 1);
27 | T shortEma = input[0];
28 | T longEma = input[0];
29 | int ppoIndex = default;
30 | for (var i = 1; i < size; ++i)
31 | {
32 | shortEma = (input[i] - shortEma) * shortPer + shortEma;
33 | longEma = (input[i] - longEma) * longPer + longEma;
34 | T outEma = THundred * (shortEma - longEma) / longEma;
35 | output[ppoIndex++] = outEma;
36 | }
37 |
38 | return TI_OKAY;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Psar.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int PsarStart(T[] options) => 1;
6 |
7 | private static int Psar(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var accelStep = options[0];
10 | var accelMax = options[1];
11 |
12 | if (accelStep <= T.Zero || accelMax <= accelStep)
13 | {
14 | return TI_INVALID_OPTION;
15 | }
16 |
17 | if (size < 2)
18 | {
19 | return TI_OKAY;
20 | }
21 |
22 | var (high, low) = inputs;
23 | var output = outputs[0];
24 |
25 | // Try to choose if we start as short or long. There is really no right answer here.
26 | bool lng = high[0] + low[0] <= high[1] + low[1];
27 | T extreme = lng ? high[0] : low[0];
28 | T sar = lng ? low[0] : high[0];
29 |
30 | T accel = accelStep;
31 | int outputIndex = default;
32 | for (var i = 1; i < size; ++i)
33 | {
34 | sar = (extreme - sar) * accel + sar;
35 | if (lng)
36 | {
37 | if (i >= 2 && sar > low[i - 2])
38 | {
39 | sar = low[i - 2];
40 | }
41 |
42 | if (sar > low[i - 1])
43 | {
44 | sar = low[i - 1];
45 | }
46 |
47 | if (accel < accelMax && high[i] > extreme)
48 | {
49 | accel += accelStep;
50 | if (accel > accelMax)
51 | {
52 | accel = accelMax;
53 | }
54 | }
55 |
56 | if (high[i] > extreme)
57 | {
58 | extreme = high[i];
59 | }
60 | }
61 | else
62 | {
63 | if (i >= 2 && sar < high[i - 2])
64 | {
65 | sar = high[i - 2];
66 | }
67 |
68 | if (sar < high[i - 1])
69 | {
70 | sar = high[i - 1];
71 | }
72 |
73 | if (accel < accelMax && low[i] < extreme)
74 | {
75 | accel += accelStep;
76 | if (accel > accelMax)
77 | {
78 | accel = accelMax;
79 | }
80 | }
81 |
82 | if (low[i] < extreme)
83 | {
84 | extreme = low[i];
85 | }
86 | }
87 |
88 | if (lng && low[i] < sar || lng == false && high[i] > sar)
89 | {
90 | accel = accelStep;
91 | sar = extreme;
92 | lng = !lng;
93 | extreme = lng ? high[i] : low[i];
94 | }
95 |
96 | output[outputIndex++] = sar;
97 | }
98 |
99 | return TI_OKAY;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Pvi.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int PviStart(T[] options) => 0;
6 |
7 | private static int Pvi(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | if (size <= PviStart(options))
10 | {
11 | return TI_OKAY;
12 | }
13 |
14 | var (close, volume) = inputs;
15 | var output = outputs[0];
16 |
17 | T pvi = T.CreateChecked(1000);
18 | int outputIndex = default;
19 | output[outputIndex++] = pvi;
20 | for (var i = 1; i < size; ++i)
21 | {
22 | if (volume[i] > volume[i - 1])
23 | {
24 | pvi += (close[i] - close[i - 1]) / close[i - 1] * pvi;
25 | }
26 |
27 | output[outputIndex++] = pvi;
28 | }
29 |
30 | return TI_OKAY;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Qstick.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int QstickStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Qstick(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= QstickStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (open, close) = inputs;
22 | var output = outputs[0];
23 |
24 | T sum = T.Zero;
25 | for (var i = 0; i < period; ++i)
26 | {
27 | sum += close[i] - open[i];
28 | }
29 |
30 | T scale = T.One / T.CreateChecked(period);
31 | int outputIndex = default;
32 | output[outputIndex++] = sum * scale;
33 | for (var i = period; i < size; ++i)
34 | {
35 | sum = sum + (close[i] - open[i]) - (close[i - period] - open[i - period]);
36 | output[outputIndex++] = sum * scale;
37 | }
38 |
39 | return TI_OKAY;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Roc.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int RocStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int Roc(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= RocStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | int outputIndex = default;
25 | for (var i = period; i < size; ++i)
26 | {
27 | output[outputIndex++] = (input[i] - input[i - period]) / input[i - period];
28 | }
29 |
30 | return TI_OKAY;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_RocR.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int RocRStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int RocR(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= RocRStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | int outputIndex = default;
25 | for (var i = period; i < size; ++i)
26 | {
27 | output[outputIndex++] = input[i] / input[i - period];
28 | }
29 |
30 | return TI_OKAY;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Round.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int RoundStart(T[] options) => 0;
6 |
7 | private static int Round(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Round);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Rsi.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int RsiStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int Rsi(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= RsiStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T smoothUp = T.Zero;
25 | T smoothDown = T.Zero;
26 | for (var i = 1; i <= period; ++i)
27 | {
28 | T upward = input[i] > input[i - 1] ? input[i] - input[i - 1] : T.Zero;
29 | T downward = input[i] < input[i - 1] ? input[i - 1] - input[i] : T.Zero;
30 | smoothUp += upward;
31 | smoothDown += downward;
32 | }
33 |
34 | smoothUp /= T.CreateChecked(period);
35 | smoothDown /= T.CreateChecked(period);
36 |
37 | T per = T.One / T.CreateChecked(period);
38 | int outputIndex = default;
39 | output[outputIndex++] = THundred * (smoothUp / (smoothUp + smoothDown));
40 | for (var i = period + 1; i < size; ++i)
41 | {
42 | T upward = input[i] > input[i - 1] ? input[i] - input[i - 1] : T.Zero;
43 | T downward = input[i] < input[i - 1] ? input[i - 1] - input[i] : T.Zero;
44 | smoothUp = (upward - smoothUp) * per + smoothUp;
45 | smoothDown = (downward - smoothDown) * per + smoothDown;
46 | output[outputIndex++] = THundred * (smoothUp / (smoothUp + smoothDown));
47 | }
48 |
49 | return TI_OKAY;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Sin.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T : IFloatingPointIeee754
4 | {
5 | private static int SinStart(T[] options) => 0;
6 |
7 | private static int Sin(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Sin);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Sinh.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int SinhStart(T[] options) => 0;
6 |
7 | private static int Sinh(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Sinh);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Sma.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int SmaStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Sma(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= SmaStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T sum = T.Zero;
25 | for (var i = 0; i < period; ++i)
26 | {
27 | sum += input[i];
28 | }
29 |
30 | T scale = T.One / T.CreateChecked(period);
31 | int outputIndex = default;
32 | output[outputIndex++] = sum * scale;
33 | for (var i = period; i < size; ++i)
34 | {
35 | sum = sum + input[i] - input[i - period];
36 | output[outputIndex++] = sum * scale;
37 | }
38 |
39 | return TI_OKAY;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Sqrt.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int SqrtStart(T[] options) => 0;
6 |
7 | private static int Sqrt(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Sqrt);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_StdDev.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int StdDevStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int StdDev(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= StdDevStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T sum = T.Zero;
25 | T sum2 = T.Zero;
26 | for (var i = 0; i < period; ++i)
27 | {
28 | sum += input[i];
29 | sum2 += input[i] * input[i];
30 | }
31 |
32 | T scale = T.One / T.CreateChecked(period);
33 | T s2S2 = sum2 * scale - sum * scale * (sum * scale);
34 | if (s2S2 > T.Zero)
35 | {
36 | s2S2 = T.Sqrt(s2S2);
37 | }
38 |
39 | int outputIndex = default;
40 | output[outputIndex++] = s2S2;
41 | for (var i = period; i < size; ++i)
42 | {
43 | sum += input[i];
44 | sum2 += input[i] * input[i];
45 |
46 | sum -= input[i - period];
47 | sum2 -= input[i - period] * input[i - period];
48 | s2S2 = sum2 * scale - sum * scale * (sum * scale);
49 | if (s2S2 > T.Zero)
50 | {
51 | s2S2 = T.Sqrt(s2S2);
52 | }
53 |
54 | output[outputIndex++] = s2S2;
55 | }
56 |
57 | return TI_OKAY;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_StdErr.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int StdErrStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int StdErr(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= StdErrStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T sum = T.Zero;
25 | T sum2 = T.Zero;
26 | for (var i = 0; i < period; ++i)
27 | {
28 | sum += input[i];
29 | sum2 += input[i] * input[i];
30 | }
31 |
32 | T scale = T.One / T.CreateChecked(period);
33 | T s2S2 = sum2 * scale - sum * scale * (sum * scale);
34 | if (s2S2 > T.Zero)
35 | {
36 | s2S2 = T.Sqrt(s2S2);
37 | }
38 |
39 | T mul = T.One / T.Sqrt(T.CreateChecked(period));
40 | int outputIndex = default;
41 | output[outputIndex++] = mul * s2S2;
42 | for (var i = period; i < size; ++i)
43 | {
44 | sum += input[i];
45 | sum2 += input[i] * input[i];
46 |
47 | sum -= input[i - period];
48 | sum2 -= input[i - period] * input[i - period];
49 | s2S2 = sum2 * scale - sum * scale * (sum * scale);
50 | if (s2S2 > T.Zero)
51 | {
52 | s2S2 = T.Sqrt(s2S2);
53 | }
54 |
55 | output[outputIndex++] = mul * s2S2;
56 | }
57 |
58 | return TI_OKAY;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Stoch.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int StochStart(T[] options) =>
6 | Int32.CreateTruncating(options[0]) + Int32.CreateTruncating(options[1]) + Int32.CreateTruncating(options[2]) - 3;
7 |
8 | private static int Stoch(int size, T[][] inputs, T[] options, T[][] outputs)
9 | {
10 | var kPeriod = Int32.CreateTruncating(options[0]);
11 | var kSlow = Int32.CreateTruncating(options[1]);
12 | var dPeriod = Int32.CreateTruncating(options[2]);
13 |
14 | if (kPeriod < 1 || kSlow < 1 || dPeriod < 1)
15 | {
16 | return TI_INVALID_OPTION;
17 | }
18 |
19 | if (size <= StochStart(options))
20 | {
21 | return TI_OKAY;
22 | }
23 |
24 | var (high, low, close) = inputs;
25 | var (stoch, stochMa) = outputs;
26 |
27 | T kPer = T.One / T.CreateChecked(kSlow);
28 | T dPer = T.One / T.CreateChecked(dPeriod);
29 |
30 | int trail = default;
31 | var maxi = -1;
32 | var mini = -1;
33 | T max = high[0];
34 | T min = low[0];
35 | var kSum = BufferFactory(kSlow);
36 | var dSum = BufferFactory(dPeriod);
37 | int stochIndex = default;
38 | int stochMaIndex = default;
39 | for (var i = 0; i < size; ++i)
40 | {
41 | if (i >= kPeriod)
42 | {
43 | ++trail;
44 | }
45 |
46 | // Maintain highest.
47 | T bar = high[i];
48 | if (maxi < trail)
49 | {
50 | maxi = trail;
51 | max = high[maxi];
52 | int j = trail;
53 | while (++j <= i)
54 | {
55 | bar = high[j];
56 | if (bar >= max)
57 | {
58 | max = bar;
59 | maxi = j;
60 | }
61 | }
62 | }
63 | else if (bar >= max)
64 | {
65 | maxi = i;
66 | max = bar;
67 | }
68 |
69 | // Maintain lowest.
70 | bar = low[i];
71 | if (mini < trail)
72 | {
73 | mini = trail;
74 | min = low[mini];
75 | int j = trail;
76 | while (++j <= i)
77 | {
78 | bar = low[j];
79 | if (bar <= min)
80 | {
81 | min = bar;
82 | mini = j;
83 | }
84 | }
85 | }
86 | else if (bar <= min)
87 | {
88 | mini = i;
89 | min = bar;
90 | }
91 |
92 | // Calculate it.
93 | T kDiff = max - min;
94 | T kFast = T.IsZero(kDiff) ? T.Zero : THundred * ((close[i] - min) / kDiff);
95 | BufferPush(ref kSum, kFast);
96 |
97 | if (i >= kPeriod - 1 + kSlow - 1)
98 | {
99 | T k = kSum.sum * kPer;
100 | BufferPush(ref dSum, k);
101 |
102 | if (i >= kPeriod - 1 + kSlow - 1 + dPeriod - 1)
103 | {
104 | stoch[stochIndex++] = k;
105 | stochMa[stochMaIndex++] = dSum.sum * dPer;
106 | }
107 | }
108 | }
109 |
110 | return TI_OKAY;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_StochRsi.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int StochRsiStart(T[] options) => Int32.CreateTruncating(options[0]) * 2 - 1;
6 |
7 | private static int StochRsi(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 2)
12 | {
13 | // if period = 0 then min-max = 0.
14 | return TI_INVALID_OPTION;
15 | }
16 |
17 | if (size <= StochRsiStart(options))
18 | {
19 | return TI_OKAY;
20 | }
21 |
22 | var input = inputs[0];
23 | var output = outputs[0];
24 |
25 | var rsi = BufferFactory(period);
26 |
27 | T smoothUp = T.Zero;
28 | T smoothDown = T.Zero;
29 | for (var i = 1; i <= period; ++i)
30 | {
31 | T upward = input[i] > input[i - 1] ? input[i] - input[i - 1] : T.Zero;
32 | T downward = input[i] < input[i - 1] ? input[i - 1] - input[i] : T.Zero;
33 | smoothUp += upward;
34 | smoothDown += downward;
35 | }
36 |
37 | smoothUp /= T.CreateChecked(period);
38 | smoothDown /= T.CreateChecked(period);
39 |
40 | T r = THundred * (smoothUp / (smoothUp + smoothDown));
41 | BufferPush(ref rsi, r);
42 |
43 | T per = T.One / T.CreateChecked(period);
44 | T min = r;
45 | T max = r;
46 | int mini = default;
47 | int maxi = default;
48 | int outputIndex = default;
49 | for (var i = period + 1; i < size; ++i)
50 | {
51 | T upward = input[i] > input[i - 1] ? input[i] - input[i - 1] : T.Zero;
52 | T downward = input[i] < input[i - 1] ? input[i - 1] - input[i] : T.Zero;
53 |
54 | smoothUp = (upward - smoothUp) * per + smoothUp;
55 | smoothDown = (downward - smoothDown) * per + smoothDown;
56 |
57 | r = THundred * (smoothUp / (smoothUp + smoothDown));
58 |
59 | if (r > max)
60 | {
61 | max = r;
62 | maxi = rsi.index;
63 | }
64 | else if (maxi == rsi.index)
65 | {
66 | max = r;
67 | for (var j = 0; j < rsi.size; ++j)
68 | {
69 | if (j == rsi.index)
70 | {
71 | continue;
72 | }
73 |
74 | if (rsi.vals[j] > max)
75 | {
76 | max = rsi.vals[j];
77 | maxi = j;
78 | }
79 | }
80 | }
81 |
82 | if (r < min)
83 | {
84 | min = r;
85 | mini = rsi.index;
86 | }
87 | else if (mini == rsi.index)
88 | {
89 | min = r;
90 | for (var j = 0; j < rsi.size; ++j)
91 | {
92 | if (j == rsi.index)
93 | {
94 | continue;
95 | }
96 |
97 | if (rsi.vals[j] < min)
98 | {
99 | min = rsi.vals[j];
100 | mini = j;
101 | }
102 | }
103 | }
104 |
105 | BufferQPush(ref rsi, r);
106 |
107 | if (i > period * 2 - 2)
108 | {
109 | T diff = max - min;
110 | output[outputIndex++] = T.IsZero(diff) ? T.Zero : (r - min) / diff;
111 | }
112 | }
113 |
114 | return TI_OKAY;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Sub.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int SubStart(T[] options) => 0;
6 |
7 | private static int Sub(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple2(size, inputs[0], inputs[1], outputs[0], (d1, d2) => d1 - d2);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Sum.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int SumStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Sum(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= SumStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T sum = T.Zero;
25 | for (var i = 0; i < period; ++i)
26 | {
27 | sum += input[i];
28 | }
29 |
30 | int outputIndex = default;
31 | output[outputIndex++] = sum;
32 | for (var i = period; i < size; ++i)
33 | {
34 | sum = sum + input[i] - input[i - period];
35 | output[outputIndex++] = sum;
36 | }
37 |
38 | return TI_OKAY;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Tan.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int TanStart(T[] options) => 0;
6 |
7 | private static int Tan(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Tan);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Tanh.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int TanhStart(T[] options) => 0;
6 |
7 | private static int Tanh(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Tanh);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Tema.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int TemaStart(T[] options) => (Int32.CreateTruncating(options[0]) - 1) * 3;
6 |
7 | private static int Tema(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= TemaStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T per = TTwo / T.CreateChecked(period + 1);
25 | T per1 = T.One - per;
26 | // Calculate EMA(input)
27 | T ema = input[0];
28 |
29 | // Calculate EMA(EMA(input))
30 | T ema2 = T.Zero;
31 |
32 | // Calculate EMA(EMA(EMA(input)))
33 | T ema3 = T.Zero;
34 | int outputIndex = default;
35 | for (var i = 0; i < size; ++i)
36 | {
37 | ema = ema * per1 + input[i] * per;
38 | if (i == period - 1)
39 | {
40 | ema2 = ema;
41 | }
42 |
43 | if (i >= period - 1)
44 | {
45 | ema2 = ema2 * per1 + ema * per;
46 | if (i == (period - 1) * 2)
47 | {
48 | ema3 = ema2;
49 | }
50 |
51 | if (i >= (period - 1) * 2)
52 | {
53 | ema3 = ema3 * per1 + ema2 * per;
54 | if (i >= (period - 1) * 3)
55 | {
56 | output[outputIndex++] = TThree * ema - TThree * ema2 + ema3;
57 | }
58 | }
59 | }
60 | }
61 |
62 | return TI_OKAY;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_ToDeg.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int ToDegStart(T[] options) => 0;
6 |
7 | private static int ToDeg(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.RadiansToDegrees);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_ToRad.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int ToRadStart(T[] options) => 0;
6 |
7 | private static int ToRad(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.DegreesToRadians);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Tr.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int TrStart(T[] options) => 0;
6 |
7 | private static int Tr(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var (high, low, close) = inputs;
10 | var output = outputs[0];
11 |
12 | output[0] = high[0] - low[0];
13 | for (var i = 1; i < size; ++i)
14 | {
15 | CalcTrueRange(low, high, close, i, out T trueRange);
16 | output[i] = trueRange;
17 | }
18 |
19 | return TI_OKAY;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Trima.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int TrimaStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Trima(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= TrimaStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | if (period <= 2)
22 | {
23 | return Sma(size, inputs, options, outputs);
24 | }
25 |
26 | var input = inputs[0];
27 | var output = outputs[0];
28 |
29 | T weightSum = T.Zero; // Weighted sum of previous numbers, spans one period back.
30 | T leadSum = T.Zero; // Flat sum of most recent numbers.
31 | T trailSum = T.Zero; // Flat sum of oldest numbers.
32 | int leadPeriod = period % 2 == 0 ? period / 2 - 1 : period / 2;
33 | int trailPeriod = leadPeriod + 1;
34 | int w = 1;
35 | for (var i = 0; i < period - 1; ++i)
36 | {
37 | weightSum += input[i] * T.CreateChecked(w);
38 | if (i + 1 > period - leadPeriod)
39 | {
40 | leadSum += input[i];
41 | }
42 |
43 | if (i + 1 <= trailPeriod)
44 | {
45 | trailSum += input[i];
46 | }
47 |
48 | if (i + 1 < trailPeriod)
49 | {
50 | ++w;
51 | }
52 |
53 | if (i + 1 >= period - leadPeriod)
54 | {
55 | --w;
56 | }
57 | }
58 |
59 | // Weights for 6 period TRIMA: 1 2 3 3 2 1 = 12
60 | // Weights for 7 period TRIMA: 1 2 3 4 3 2 1 = 16
61 | T weights = T.One / T.CreateChecked(period % 2 != 0 ? (period / 2 + 1) * (period / 2 + 1) : (period / 2 + 1) * (period / 2));
62 | int lsi = period - leadPeriod;
63 | int tsi1 = period - period + trailPeriod;
64 | int tsi2 = period - period;
65 | int outputIndex = default;
66 | // Initialize until before the first value.
67 | for (var i = period - 1; i < size; ++i)
68 | {
69 | weightSum += input[i];
70 | output[outputIndex++] = weightSum * weights;
71 |
72 | leadSum += input[i];
73 |
74 | // 1 2 3 4 5 4 3 2 1
75 | weightSum += leadSum;
76 | // 1 2 3 4 5 5 4 3 2
77 | weightSum -= trailSum;
78 | // 1 2 3 4 5 4 3 2
79 |
80 | /* weightSum 1 2 3 4 5 4 3 2 1
81 | leadSum 1 1 1 1
82 | trailSum 1 1 1 1 1 */
83 | leadSum -= input[lsi++];
84 | trailSum += input[tsi1++];
85 | trailSum -= input[tsi2++];
86 | }
87 |
88 | return TI_OKAY;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Trix.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int TrixStart(T[] options) => (Int32.CreateTruncating(options[0]) - 1) * 3 + 1;
6 |
7 | private static int Trix(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= TrixStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | int start = period * 3 - 2;
25 | T per = TTwo / T.CreateChecked(period + 1);
26 | T ema1 = input[0];
27 | T ema2 = T.Zero;
28 | T ema3 = T.Zero;
29 | for (var i = 1; i < start; ++i)
30 | {
31 | ema1 = (input[i] - ema1) * per + ema1;
32 | if (i == period - 1)
33 | {
34 | ema2 = ema1;
35 | }
36 | else if (i > period - 1)
37 | {
38 | ema2 = (ema1 - ema2) * per + ema2;
39 | if (i == period * 2 - 2)
40 | {
41 | ema3 = ema2;
42 | }
43 | else if (i > period * 2 - 2)
44 | {
45 | ema3 = (ema2 - ema3) * per + ema3;
46 | }
47 | }
48 | }
49 |
50 | int outputIndex = default;
51 | for (int i = start; i < size; ++i)
52 | {
53 | ema1 = (input[i] - ema1) * per + ema1;
54 | ema2 = (ema1 - ema2) * per + ema2;
55 | T last = ema3;
56 | ema3 = (ema2 - ema3) * per + ema3;
57 | output[outputIndex++] = (ema3 - last) / ema3 * THundred;
58 | }
59 |
60 | return TI_OKAY;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Trunc.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int TruncStart(T[] options) => 0;
6 |
7 | private static int Trunc(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | Simple1(size, inputs[0], outputs[0], T.Truncate);
10 |
11 | return TI_OKAY;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Tsf.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int TsfStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Tsf(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= TsfStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T x = T.Zero; // Sum of Xs.
25 | T x2 = T.Zero; // Sum of square of Xs.
26 | T y = T.Zero; // Flat sum of previous numbers.
27 | T xy = T.Zero; // Weighted sum of previous numbers.
28 | for (var i = 0; i < period - 1; ++i)
29 | {
30 | x += T.CreateChecked(i + 1);
31 | x2 += T.CreateChecked((i + 1) * (i + 1));
32 | xy += input[i] * T.CreateChecked(i + 1);
33 | y += input[i];
34 | }
35 |
36 | x += T.CreateChecked(period);
37 | x2 += T.CreateChecked(period * period);
38 |
39 | T p = T.One / T.CreateChecked(period);
40 | T bd = T.One / (T.CreateChecked(period) * x2 - x * x);
41 | int outputIndex = default;
42 | for (var i = period - 1; i < size; ++i)
43 | {
44 | xy += input[i] * T.CreateChecked(period);
45 | y += input[i];
46 | T b = (T.CreateChecked(period) * xy - x * y) * bd;
47 | T a = (y - b * x) * p;
48 | output[outputIndex++] = a + b * T.CreateChecked(period + 1);
49 | xy -= y;
50 | y -= input[i - period + 1];
51 | }
52 |
53 | return TI_OKAY;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_TypPrice.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int TypPriceStart(T[] options) => 0;
6 |
7 | private static int TypPrice(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var (high, low, close) = inputs;
10 | var output = outputs[0];
11 |
12 | for (var i = 0; i < size; ++i)
13 | {
14 | output[i] = (high[i] + low[i] + close[i]) * (T.One / TThree);
15 | }
16 |
17 | return TI_OKAY;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_UltOsc.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int UltOscStart(T[] options) => Int32.CreateTruncating(options[2]);
6 |
7 | private static int UltOsc(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var shortPeriod = Int32.CreateTruncating(options[0]);
10 | var mediumPeriod = Int32.CreateTruncating(options[1]);
11 | var longPeriod = Int32.CreateTruncating(options[2]);
12 |
13 | if (shortPeriod < 1 || mediumPeriod < shortPeriod || longPeriod < mediumPeriod)
14 | {
15 | return TI_INVALID_OPTION;
16 | }
17 |
18 | if (size <= UltOscStart(options))
19 | {
20 | return TI_OKAY;
21 | }
22 |
23 | var (high, low, close) = inputs;
24 | var output = outputs[0];
25 |
26 | var bpBuf = BufferFactory(longPeriod);
27 | var rBuf = BufferFactory(longPeriod);
28 | T bpShortSum = T.Zero;
29 | T bpMediumSum = T.Zero;
30 | T rShortSum = T.Zero;
31 | T rMediumSum = T.Zero;
32 | int outputIndex = default;
33 | for (var i = 1; i < size; ++i)
34 | {
35 | T trueLow = T.Min(low[i], close[i - 1]);
36 | T trueHigh = T.Max(high[i], close[i - 1]);
37 | T bp = close[i] - trueLow;
38 | T r = trueHigh - trueLow;
39 | bpShortSum += bp;
40 | bpMediumSum += bp;
41 | rShortSum += r;
42 | rMediumSum += r;
43 |
44 | BufferPush(ref bpBuf, bp);
45 | BufferPush(ref rBuf, r);
46 |
47 | // The long sum takes care of itself, but we're piggy-backing the medium and short sums off the same buffers.
48 | if (i > shortPeriod)
49 | {
50 | int shortIndex = bpBuf.index - shortPeriod - 1;
51 | if (shortIndex < 0)
52 | {
53 | shortIndex += longPeriod;
54 | }
55 |
56 | bpShortSum -= bpBuf.vals[shortIndex];
57 | rShortSum -= rBuf.vals[shortIndex];
58 | if (i > mediumPeriod)
59 | {
60 | int mediumIndex = bpBuf.index - mediumPeriod - 1;
61 | if (mediumIndex < 0)
62 | {
63 | mediumIndex += longPeriod;
64 | }
65 |
66 | bpMediumSum -= bpBuf.vals[mediumIndex];
67 | rMediumSum -= rBuf.vals[mediumIndex];
68 | }
69 | }
70 |
71 | if (i >= longPeriod)
72 | {
73 | T first = T.CreateChecked(4) * bpShortSum / rShortSum;
74 | T second = TTwo * bpMediumSum / rMediumSum;
75 | T third = T.One * bpBuf.sum / rBuf.sum;
76 | T ult = (first + second + third) * THundred / T.CreateChecked(7);
77 | output[outputIndex++] = ult;
78 | }
79 | }
80 |
81 | return TI_OKAY;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Var.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int VarStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Var(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= VarStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T sum = T.Zero;
25 | T sum2 = T.Zero;
26 | for (var i = 0; i < period; ++i)
27 | {
28 | sum += input[i];
29 | sum2 += input[i] * input[i];
30 | }
31 |
32 | T scale = T.One / T.CreateChecked(period);
33 | int outputIndex = default;
34 | output[outputIndex++] = sum2 * scale - sum * scale * (sum * scale);
35 | for (var i = period; i < size; ++i)
36 | {
37 | sum += input[i];
38 | sum2 += input[i] * input[i];
39 |
40 | sum -= input[i - period];
41 | sum2 -= input[i - period] * input[i - period];
42 |
43 | output[outputIndex++] = sum2 * scale - sum * scale * (sum * scale);
44 | }
45 |
46 | return TI_OKAY;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Vhf.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int VhfStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int Vhf(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= VhfStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T sum = T.Zero;
25 | T yc = input[0];
26 | for (var i = 1; i < period; ++i)
27 | {
28 | T c = input[i];
29 | sum += T.Abs(c - yc);
30 | yc = c;
31 | }
32 |
33 | var maxi = -1;
34 | var mini = -1;
35 | T max = input[0];
36 | T min = input[0];
37 | int outputIndex = default;
38 | for (int i = period, trail = 1; i < size; ++i, ++trail)
39 | {
40 | T c = input[i];
41 | sum += T.Abs(c - yc);
42 | yc = c;
43 | if (i > period)
44 | {
45 | sum -= T.Abs(input[i - period] - input[i - period - 1]);
46 | }
47 |
48 | // Maintain highest.
49 | T bar = c;
50 | if (maxi < trail)
51 | {
52 | maxi = trail;
53 | max = input[maxi];
54 | int j = trail;
55 | while (++j <= i)
56 | {
57 | bar = input[j];
58 | if (bar >= max)
59 | {
60 | max = bar;
61 | maxi = j;
62 | }
63 | }
64 | }
65 | else if (bar >= max)
66 | {
67 | maxi = i;
68 | max = bar;
69 | }
70 |
71 | // Maintain lowest.
72 | bar = c;
73 | if (mini < trail)
74 | {
75 | mini = trail;
76 | min = input[mini];
77 | int j = trail;
78 | while (++j <= i)
79 | {
80 | bar = input[j];
81 | if (bar <= min)
82 | {
83 | min = bar;
84 | mini = j;
85 | }
86 | }
87 | }
88 | else if (bar <= min)
89 | {
90 | mini = i;
91 | min = bar;
92 | }
93 |
94 | // Calculate it.
95 | output[outputIndex++] = T.Abs(max - min) / sum;
96 | }
97 |
98 | return TI_OKAY;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Vidya.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int VidyaStart(T[] options) => Int32.CreateTruncating(options[1]) - 2;
6 |
7 | private static int Vidya(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var shortPeriod = Int32.CreateTruncating(options[0]);
10 | var longPeriod = Int32.CreateTruncating(options[1]);
11 | var alpha = options[2];
12 |
13 | if (shortPeriod < 1 || longPeriod < shortPeriod || longPeriod < 2 || alpha < T.Zero || alpha > T.One)
14 | {
15 | return TI_INVALID_OPTION;
16 | }
17 |
18 | if (size <= VidyaStart(options))
19 | {
20 | return TI_OKAY;
21 | }
22 |
23 | var input = inputs[0];
24 | var output = outputs[0];
25 |
26 | T shortSum = T.Zero;
27 | T shortSum2 = T.Zero;
28 | T longSum = T.Zero;
29 | T longSum2 = T.Zero;
30 | for (var i = 0; i < longPeriod; ++i)
31 | {
32 | longSum += input[i];
33 | longSum2 += input[i] * input[i];
34 | if (i >= longPeriod - shortPeriod)
35 | {
36 | shortSum += input[i];
37 | shortSum2 += input[i] * input[i];
38 | }
39 | }
40 |
41 | T shortDiv = T.One / T.CreateChecked(shortPeriod);
42 | T longDiv = T.One / T.CreateChecked(longPeriod);
43 | T val = input[longPeriod - 2];
44 | int outputIndex = default;
45 | output[outputIndex++] = val;
46 | if (longPeriod - 1 < size)
47 | {
48 | var shortStdDev = T.Sqrt(shortSum2 * shortDiv - shortSum * shortDiv * (shortSum * shortDiv));
49 | var longStdDev = T.Sqrt(longSum2 * longDiv - longSum * longDiv * (longSum * longDiv));
50 | T k = shortStdDev / longStdDev;
51 |
52 | k *= alpha;
53 | val = (input[longPeriod - 1] - val) * k + val;
54 | output[outputIndex++] = val;
55 | }
56 |
57 | for (var i = longPeriod; i < size; ++i)
58 | {
59 | longSum += input[i];
60 | longSum2 += input[i] * input[i];
61 |
62 | shortSum += input[i];
63 | shortSum2 += input[i] * input[i];
64 |
65 | longSum -= input[i - longPeriod];
66 | longSum2 -= input[i - longPeriod] * input[i - longPeriod];
67 |
68 | shortSum -= input[i - shortPeriod];
69 | shortSum2 -= input[i - shortPeriod] * input[i - shortPeriod];
70 |
71 | T shortStdDev = T.Sqrt(shortSum2 * shortDiv - shortSum * shortDiv * (shortSum * shortDiv));
72 | T longStdDev = T.Sqrt(longSum2 * longDiv - longSum * longDiv * (longSum * longDiv));
73 | T k = shortStdDev / longStdDev;
74 |
75 | k *= alpha;
76 | val = (input[i] - val) * k + val;
77 | output[outputIndex++] = val;
78 | }
79 |
80 | return TI_OKAY;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Volatility.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int VolatilityStart(T[] options) => Int32.CreateTruncating(options[0]);
6 |
7 | private static int Volatility(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= VolatilityStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T sum = T.Zero;
25 | T sum2 = T.Zero;
26 | for (var i = 1; i <= period; ++i)
27 | {
28 | T c = input[i] / input[i - 1] - T.One;
29 | sum += c;
30 | sum2 += c * c;
31 | }
32 |
33 | T scale = T.One / T.CreateChecked(period);
34 | T annual = T.Sqrt(T.CreateChecked(252)); // Multiplier, number of trading days in year.
35 | int outputIndex = default;
36 | output[outputIndex++] = T.Sqrt(sum2 * scale - sum * scale * (sum * scale)) * annual;
37 | for (var i = period + 1; i < size; ++i)
38 | {
39 | T c = input[i] / input[i - 1] - T.One;
40 | sum += c;
41 | sum2 += c * c;
42 |
43 | T cp = input[i - period] / input[i - period - 1] - T.One;
44 | sum -= cp;
45 | sum2 -= cp * cp;
46 |
47 | output[outputIndex++] = T.Sqrt(sum2 * scale - sum * scale * (sum * scale)) * annual;
48 | }
49 |
50 | return TI_OKAY;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Vosc.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int VoscStart(T[] options) => Int32.CreateTruncating(options[1]) - 1;
6 |
7 | private static int Vosc(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var shortPeriod = Int32.CreateTruncating(options[0]);
10 | var longPeriod = Int32.CreateTruncating(options[1]);
11 |
12 | if (shortPeriod < 1 || longPeriod < shortPeriod)
13 | {
14 | return TI_INVALID_OPTION;
15 | }
16 |
17 | if (size <= VoscStart(options))
18 | {
19 | return TI_OKAY;
20 | }
21 |
22 | var input = inputs[0];
23 | var output = outputs[0];
24 |
25 | T shortSum = T.Zero;
26 | T longSum = T.Zero;
27 | for (var i = 0; i < longPeriod; ++i)
28 | {
29 | if (i >= longPeriod - shortPeriod)
30 | {
31 | shortSum += input[i];
32 | }
33 |
34 | longSum += input[i];
35 | }
36 |
37 | T shortDiv = T.One / T.CreateChecked(shortPeriod);
38 | T longDiv = T.One / T.CreateChecked(longPeriod);
39 | T savg = shortSum * shortDiv;
40 | T lavg = longSum * longDiv;
41 | int outputIndex = default;
42 | output[outputIndex++] = THundred * (savg - lavg) / lavg;
43 | for (var i = longPeriod; i < size; ++i)
44 | {
45 | shortSum += input[i];
46 | shortSum -= input[i - shortPeriod];
47 |
48 | longSum += input[i];
49 | longSum -= input[i - longPeriod];
50 |
51 | savg = shortSum * shortDiv;
52 | lavg = longSum * longDiv;
53 | output[outputIndex++] = THundred * (savg - lavg) / lavg;
54 | }
55 |
56 | return TI_OKAY;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Vwma.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int VwmaStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Vwma(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= VwmaStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (input, volume) = inputs;
22 | var output = outputs[0];
23 |
24 | T sum = T.Zero;
25 | T vSum = T.Zero;
26 | for (var i = 0; i < period; ++i)
27 | {
28 | sum += input[i] * volume[i];
29 | vSum += volume[i];
30 | }
31 |
32 | int outputIndex = default;
33 | output[outputIndex++] = sum / vSum;
34 | for (var i = period; i < size; ++i)
35 | {
36 | sum += input[i] * volume[i];
37 | sum -= input[i - period] * volume[i - period];
38 | vSum += volume[i];
39 | vSum -= volume[i - period];
40 |
41 | output[outputIndex++] = sum / vSum;
42 | }
43 |
44 | return TI_OKAY;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Wad.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int WadStart(T[] options) => 1;
6 |
7 | private static int Wad(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | if (size <= WadStart(options))
10 | {
11 | return TI_OKAY;
12 | }
13 |
14 | var (high, low, close) = inputs;
15 | var output = outputs[0];
16 |
17 | T sum = T.Zero;
18 | T yc = close[0];
19 | int outputIndex = default;
20 | for (var i = 1; i < size; ++i)
21 | {
22 | T c = close[i];
23 | if (c > yc)
24 | {
25 | sum += c - T.Min(yc, low[i]);
26 | }
27 | else if (c < yc)
28 | {
29 | sum += c - T.Max(yc, high[i]);
30 | }
31 |
32 | output[outputIndex++] = sum;
33 | yc = close[i];
34 | }
35 |
36 | return TI_OKAY;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_WcPrice.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int WcPriceStart(T[] options) => 0;
6 |
7 | private static int WcPrice(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var (high, low, close) = inputs;
10 | var output = outputs[0];
11 |
12 | for (var i = 0; i < size; ++i)
13 | {
14 | output[i] = (high[i] + low[i] + close[i] + close[i]) * T.CreateChecked(0.25);
15 | }
16 |
17 | return TI_OKAY;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Wilders.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int WildersStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Wilders(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= WildersStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T sum = T.Zero;
25 | for (var i = 0; i < period; ++i)
26 | {
27 | sum += input[i];
28 | }
29 |
30 | T per = T.One / T.CreateChecked(period);
31 | T val = sum / T.CreateChecked(period);
32 | int outputIndex = default;
33 | output[outputIndex++] = val;
34 | for (var i = period; i < size; ++i)
35 | {
36 | val = (input[i] - val) * per + val;
37 | output[outputIndex++] = val;
38 | }
39 |
40 | return TI_OKAY;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_WillR.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int WillRStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int WillR(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= WillRStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var (high, low, close) = inputs;
22 | var output = outputs[0];
23 |
24 | var maxi = -1;
25 | var mini = -1;
26 | T max = high[0];
27 | T min = low[0];
28 | int outputIndex = default;
29 | for (int i = period - 1, trail = 0; i < size; ++i, ++trail)
30 | {
31 | // Maintain highest.
32 | T bar = high[i];
33 | if (maxi < trail)
34 | {
35 | maxi = trail;
36 | max = high[maxi];
37 | int j = trail;
38 | while (++j <= i)
39 | {
40 | bar = high[j];
41 | if (bar >= max)
42 | {
43 | max = bar;
44 | maxi = j;
45 | }
46 | }
47 | }
48 | else if (bar >= max)
49 | {
50 | maxi = i;
51 | max = bar;
52 | }
53 |
54 |
55 | // Maintain lowest.
56 | bar = low[i];
57 | if (mini < trail)
58 | {
59 | mini = trail;
60 | min = low[mini];
61 | int j = trail;
62 | while (++j <= i)
63 | {
64 | bar = low[j];
65 | if (bar <= min)
66 | {
67 | min = bar;
68 | mini = j;
69 | }
70 | }
71 | }
72 | else if (bar <= min)
73 | {
74 | mini = i;
75 | min = bar;
76 | }
77 |
78 | // Calculate it.
79 | T highLow = max - min;
80 | T r = T.IsZero(highLow) ? T.Zero : T.NegativeOne * THundred * ((max - close[i]) / highLow);
81 | output[outputIndex++] = r;
82 | }
83 |
84 | return TI_OKAY;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_Wma.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int WmaStart(T[] options) => Int32.CreateTruncating(options[0]) - 1;
6 |
7 | private static int Wma(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= WmaStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | T weightSum = T.Zero; // Weighted sum of previous numbers.
25 | T sum = T.Zero; // Flat sum of previous numbers.
26 | for (var i = 0; i < period - 1; ++i)
27 | {
28 | weightSum += input[i] * T.CreateChecked(i + 1);
29 | sum += input[i];
30 | }
31 |
32 | T weights = T.CreateChecked(period * (period + 1)) / TTwo; // Weights for 6 period WMA: 1 2 3 4 5 6
33 | int outputIndex = default;
34 | for (var i = period - 1; i < size; ++i)
35 | {
36 | weightSum += input[i] * T.CreateChecked(period);
37 | sum += input[i];
38 |
39 | output[outputIndex++] = weightSum / weights;
40 |
41 | weightSum -= sum;
42 | sum -= input[i - period + 1];
43 | }
44 |
45 | return TI_OKAY;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Indicators/TI_ZlEma.cs:
--------------------------------------------------------------------------------
1 | namespace Tulip;
2 |
3 | internal static partial class Tinet where T: IFloatingPointIeee754
4 | {
5 | private static int ZlEmaStart(T[] options) => (Int32.CreateTruncating(options[0]) - 1) / 2 - 1;
6 |
7 | private static int ZlEma(int size, T[][] inputs, T[] options, T[][] outputs)
8 | {
9 | var period = Int32.CreateTruncating(options[0]);
10 |
11 | if (period < 1)
12 | {
13 | return TI_INVALID_OPTION;
14 | }
15 |
16 | if (size <= ZlEmaStart(options))
17 | {
18 | return TI_OKAY;
19 | }
20 |
21 | var input = inputs[0];
22 | var output = outputs[0];
23 |
24 | var lag = (period - 1) / 2;
25 | T per = TTwo / T.CreateChecked(period + 1);
26 | T val = input[lag - 1];
27 | int outputIndex = default;
28 | output[outputIndex++] = val;
29 | for (var i = lag; i < size; ++i)
30 | {
31 | T c = input[i];
32 | T l = input[i - lag];
33 | val = (c + (c - l) - val) * per + val;
34 | output[outputIndex++] = val;
35 | }
36 |
37 | return TI_OKAY;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Tinet.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace Tulip;
4 |
5 | internal static partial class Tinet where T: IFloatingPointIeee754
6 | {
7 | private const int TI_OKAY = 0;
8 | private const int TI_INVALID_OPTION = 1;
9 |
10 | const string LookbackSuffix = "Start";
11 |
12 | private static T TTwo = T.CreateChecked(2);
13 | private static T TThree = T.CreateChecked(3);
14 | private static T THundred = T.CreateChecked(100);
15 |
16 | public static int IndicatorRun(string name, T[][] inputs, T[] options, T[][] outputs)
17 | {
18 | try
19 | {
20 | typeof(Tinet<>).MakeGenericType(typeof(T)).InvokeMember(name,
21 | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
22 | Type.DefaultBinder, null, [inputs[0].Length, inputs, options, outputs]);
23 | }
24 | catch (MissingMethodException)
25 | {
26 | return TI_INVALID_OPTION;
27 | }
28 |
29 | return TI_OKAY;
30 | }
31 |
32 | public static int IndicatorStart(string name, T[] options)
33 | {
34 | try
35 | {
36 | return Convert.ToInt32(typeof(Tinet<>).MakeGenericType(typeof(T)).InvokeMember($"{name}{LookbackSuffix}",
37 | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
38 | Type.DefaultBinder, null, [options]));
39 | }
40 | catch (MissingMethodException)
41 | {
42 | return TI_INVALID_OPTION;
43 | }
44 | }
45 |
46 | private static (int size, int pushes, int index, T sum, T[] vals) BufferFactory(int size) =>
47 | (size, 0, 0, T.Zero, new T[size]);
48 |
49 | private static void BufferPush(ref (int size, int pushes, int index, T sum, T[] vals) buffer, T val)
50 | {
51 | if (buffer.pushes >= buffer.size)
52 | {
53 | buffer.sum -= buffer.vals[buffer.index];
54 | }
55 |
56 | buffer.sum += val;
57 | buffer.vals[buffer.index++] = val;
58 | ++buffer.pushes;
59 | if (buffer.index >= buffer.size)
60 | {
61 | buffer.index = 0;
62 | }
63 | }
64 |
65 | private static void BufferQPush(ref (int size, int pushes, int index, T sum, T[] vals) buffer, T val)
66 | {
67 | buffer.vals[buffer.index++] = val;
68 | if (buffer.index >= buffer.size)
69 | {
70 | buffer.index = 0;
71 | }
72 | }
73 |
74 | private static T BufferGet((int, int, int, T, T[]) buffer, int val)
75 | {
76 | var (size, _, index, _, vals) = buffer;
77 | return vals[(Index) ((index + size - 1 + val) % size)];
78 | }
79 |
80 | private static void CalcTrueRange(T[] low, T[] high, T[] close, int i, out T trueRange)
81 | {
82 | T l = low[i];
83 | T h = high[i];
84 | T c = close[i - 1];
85 | T ych = T.Abs(h - c);
86 | T ycl = T.Abs(l - c);
87 | T v = h - l;
88 | if (ych > v)
89 | {
90 | v = ych;
91 | }
92 |
93 | if (ycl > v)
94 | {
95 | v = ycl;
96 | }
97 |
98 | trueRange = v;
99 | }
100 |
101 | private static void CalcDirection(T[] high, T[] low, int i, out T up, out T down)
102 | {
103 | up = high[i] - high[i - 1];
104 | down = low[i - 1] - low[i];
105 |
106 | if (up < T.Zero)
107 | {
108 | up = T.Zero;
109 | }
110 | else if (up > down)
111 | {
112 | down = T.Zero;
113 | }
114 |
115 | if (down < T.Zero)
116 | {
117 | down = T.Zero;
118 | }
119 | else if (down > up)
120 | {
121 | up = T.Zero;
122 | }
123 | }
124 |
125 | private static void Simple1(int size, T[] input, T[] output, Func op)
126 | {
127 | for (var i = 0; i < size; ++i)
128 | {
129 | output[i] = op(input[i]);
130 | }
131 | }
132 |
133 | private static void Simple2(int size, T[] input1, T[] input2, T[] output, Func op)
134 | {
135 | for (var i = 0; i < size; ++i)
136 | {
137 | output[i] = op(input1[i], input2[i]);
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/Tulip.NETCore/Tulip.NETCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | Tulip
6 | enable
7 | Tulip.NETCore
8 | A pure port to .NET (C#) of Tulip Indicators
9 | Anatoliy Siryi
10 | Tulip Charts LLC
11 | LICENSE
12 | https://tulipindicators.org
13 | 0.9.0
14 | https://github.com/hmG3/Tulip.NETCore
15 | git
16 | tulip.png
17 | tulip;technical;analysis;financial;data;stock;market
18 |
19 |
20 |
21 |
22 | True
23 |
24 |
25 |
26 | True
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/Tulip.NETCore.Tests/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | [assembly: ExcludeFromCodeCoverage]
4 |
--------------------------------------------------------------------------------
/tests/Tulip.NETCore.Tests/DataSets/extra.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./testdata.schema.json",
3 | "_": [
4 | {
5 | "name": "abs",
6 | "inputs": [
7 | [ -1, 1, -4, 6 ]
8 | ],
9 | "outputs": [
10 | [ 1, 1, 4, 6 ]
11 | ]
12 | },
13 | {
14 | "name": "acos",
15 | "inputs": [
16 | [ 0, 0.5, 1 ]
17 | ],
18 | "outputs": [
19 | [ 1.571, 1.047, 0 ]
20 | ]
21 | },
22 | {
23 | "name": "add",
24 | "inputs": [
25 | [ 1, 5, 4, 6, 7, 8, 5, 1, 0, 6 ],
26 | [ 9, 4, 5, 6, 2, 1, 4, 5, 7, 0 ]
27 | ],
28 | "outputs": [
29 | [ 10, 9, 9, 12, 9, 9, 9, 6, 7, 6 ]
30 | ]
31 | },
32 | {
33 | "name": "adx",
34 | "inputs": [
35 | [ 148.1150, 148.2260, 148.0270, 149.6030, 149.7390, 150.7820, 151.2470, 151.0840, 151.8550, 151.8740, 150.9770, 151.6930, 151.8770, 151.6500, 151.3160, 150.5250, 150.0720, 150.6560, 150.6690, 149.4280, 150.1440, 151.3860, 151.1880, 150.3250, 149.6250, 149.2370, 147.6560, 147.1880, 147.7920 ],
36 | [ 147.7340, 147.7860, 147.7870, 148.0260, 149.3680, 149.9570, 150.4670, 150.4070, 150.9670, 151.0030, 150.6900, 150.3730, 151.3120, 151.0280, 150.5250, 149.7250, 149.5620, 149.8850, 149.1220, 149.1930, 149.4970, 149.8870, 149.9450, 149.4930, 148.7150, 148.3210, 146.8740, 146.8130, 147.3350 ],
37 | [ 147.8460, 148.0270, 148.0260, 149.6030, 149.6820, 150.7820, 150.4690, 151.0840, 151.8550, 151.0030, 150.6900, 151.6930, 151.3120, 151.0280, 150.5250, 149.7250, 150.0720, 150.6560, 149.1220, 149.3260, 150.1440, 151.3860, 150.2320, 149.6250, 148.8880, 148.3210, 146.8740, 147.1660, 147.7920 ]
38 | ],
39 | "options": [ 14 ],
40 | "outputs": [
41 | [ 36.6183, 34.6383, 32.173 ]
42 | ]
43 | },
44 | {
45 | "name": "ao",
46 | "inputs": [
47 | [ 32.1100, 27.6200, 28.2600, 28.0200, 26.9300, 26.6500, 27.2500, 27.5800, 27.9000, 28.9000, 29.3400, 29.8200, 29.5400, 29.3000, 29.5000, 29.5000, 29.7000, 29.1400, 27.1700, 30.3400, 30.2600, 30.1400, 29.9800, 30.5500, 32.1100, 34.1600, 39.5000, 50.7800, 51.3800, 51.3400, 50.7000, 44.2300, 42.7100, 39.8200, 42.3500, 44.7100, 44.2700, 43.6700, 44.8300, 44.5500, 46.8000, 46.2400, 45.5200, 44.5500, 46.1200, 44.7100, 44.4700, 45.2800, 44.6300, 43.4300, 46.2400, 49.1300, 49.9300, 49.9300, 51.3800, 52.7800, 50.5300, 50.6100, 49.3300, 49.4100, 53.3000, 52.5800, 62.3000, 61.5700, 62.5400, 64.5400, 74.1400, 73.1700, 70.1200, 68.6400, 71.7700, 70.6400, 71.7700, 104.0400, 103.4000, 97.6200, 98.9000, 99.4600, 89.2300, 87.3400, 82.2800, 78.9900, 81.5600, 78.0300, 73.8600, 77.6700, 79.4700, 77.7100, 76.7500, 78.3100, 77.7100, 72.2500, 68.0800, 66.3100, 65.7500, 64.1400, 67.4300, 80.2800, 78.3500 ],
48 | [ 25.6900, 25.5700, 25.7300, 25.6900, 25.6900, 26.1700, 26.0500, 26.2900, 26.8900, 27.7400, 28.4600, 29.0200, 28.4600, 28.7800, 29.0600, 28.7400, 28.5000, 27.0100, 26.3300, 26.9700, 29.1800, 29.6200, 29.5400, 29.7400, 30.4700, 31.8300, 34.6400, 40.4200, 47.6800, 48.9700, 43.2700, 41.5800, 38.7300, 37.3300, 37.8900, 43.3900, 42.6700, 41.1400, 42.3900, 43.0300, 43.7500, 44.8300, 43.3500, 42.6700, 43.6700, 42.6700, 43.5900, 43.1900, 43.3100, 41.5800, 42.5500, 45.9600, 47.4000, 48.1700, 48.9700, 50.2500, 48.6100, 48.3700, 48.0500, 48.0500, 49.1700, 50.9800, 49.8500, 56.5600, 57.8000, 58.8400, 64.5400, 66.3100, 63.1000, 65.0600, 66.9500, 65.8300, 67.3900, 72.2500, 84.1300, 89.9100, 93.1200, 89.9100, 83.1700, 76.3400, 72.7300, 71.9300, 75.8600, 72.5700, 67.9100, 70.0400, 75.1400, 74.6600, 72.6900, 72.8900, 70.6400, 63.6600, 57.8000, 58.9200, 52.6600, 57.8800, 62.3400, 68.7600, 67.6700 ]
49 | ],
50 | "outputs": [
51 | [ 11.6905, 9.3535, 8.2531, 7.8816, 7.7612, 8.2594, 8.4822, 8.1794, 8.0454, 7.9502, 7.5005, 7.2510, 6.5143, 5.7713, 5.2844, 4.9243, 4.0526, 3.7438, 3.8741, 4.1156, 4.5317, 5.4641, 6.2518, 6.0741, 5.6701, 5.0864, 4.3346, 3.8620, 4.1222, 5.2467, 7.0596, 8.9599, 10.4984, 13.1686, 14.9850, 15.7149, 16.3803, 17.1528, 16.1721, 15.3763, 18.3787, 22.3355, 25.7980, 29.8361, 33.3549, 31.7510, 28.2440, 24.0074, 18.9790, 14.7623, 11.6177, 8.6476, 7.1438, 6.6704, 5.3673, 4.5294, 4.7640, 4.1044, 1.6913, -1.3769, -4.2062, -7.7196, -10.6241, -11.4972, -9.6358, -7.9344 ]
52 | ]
53 | },
54 | {
55 | "name": "apo",
56 | "inputs": [
57 | [ 25, 24.875, 24.781, 24.594, 24.5, 24.625, 25.219, 27.25 ]
58 | ],
59 | "options": [ 3, 5 ],
60 | "outputs": [
61 | [ -0.0208, -0.04, -0.0709, -0.085, -0.0547, 0.0635, 0.4308 ]
62 | ]
63 | },
64 | {
65 | "name": "aroonosc",
66 | "inputs": [
67 | [ 27.5, 28.125, 29, 30.313, 29.75, 28.563, 29.831, 30.969, 30.594, 31.125, 32.5, 33.844, 34.469, 34.719, 33.031, 33.625, 34, 33.813, 33.156, 32.969, 33.813 ],
68 | [ 26.219, 26.313, 26.906, 29.188, 29.188, 26.594, 27.875, 30.25, 29.75, 29.813, 30.406, 32.844, 33.813, 32.688, 32.281, 32.281, 32.938, 32.688, 31.5, 31.375, 32.656 ]
69 | ],
70 | "options": [ 5 ],
71 | "outputs": [
72 | [ 60, 40, 40, 40, 80, 100, 100, 80, 100, 80, 60, -40, -40, -100, -60, -60 ]
73 | ]
74 | },
75 | {
76 | "name": "asin",
77 | "inputs": [
78 | [ 0, 0.5, 1 ]
79 | ],
80 | "outputs": [
81 | [ 0, 0.524, 1.571 ]
82 | ]
83 | },
84 | {
85 | "name": "atan",
86 | "inputs": [
87 | [ 0, 0.5, 1 ]
88 | ],
89 | "outputs": [
90 | [ 0, 0.464, 0.785 ]
91 | ]
92 | },
93 | {
94 | "name": "avgprice",
95 | "inputs": [
96 | [ 81.85, 81.2, 81.55, 82.91, 83.1, 83.41, 82.71, 82.7, 84.2, 84.25, 84.03, 85.45 ],
97 | [ 82.15, 81.89, 83.03, 83.3, 83.85, 83.9, 83.33, 84.3, 84.84, 85, 85.9, 86.58 ],
98 | [ 81.29, 80.64, 81.31, 82.65, 83.07, 83.11, 82.49, 82.3, 84.15, 84.11, 84.03, 85.39 ],
99 | [ 81.59, 81.06, 82.87, 83, 83.61, 83.15, 82.84, 83.99, 84.55, 84.36, 85.53, 86.54 ]
100 | ],
101 | "outputs": [
102 | [ 81.720, 81.198, 82.190, 82.965, 83.408, 83.393, 82.843, 83.323, 84.435, 84.430, 84.873, 85.990 ]
103 | ]
104 | },
105 | {
106 | "name": "bop",
107 | "inputs": [
108 | [ 81.85, 81.2, 81.55, 82.91, 83.1, 83.41, 82.71, 82.7, 84.2, 84.25, 84.03, 85.45 ],
109 | [ 82.15, 81.89, 83.03, 83.3, 83.85, 83.9, 83.33, 84.3, 84.84, 85, 85.9, 86.58 ],
110 | [ 81.29, 80.64, 81.31, 82.65, 83.07, 83.11, 82.49, 82.3, 84.15, 84.11, 84.03, 85.39 ],
111 | [ 81.59, 81.06, 82.87, 83, 83.61, 83.15, 82.84, 83.99, 84.55, 84.36, 85.53, 86.54 ]
112 | ],
113 | "outputs": [
114 | [ -0.3023, -0.112, 0.7674, 0.1385, 0.6538, -0.3291, 0.1548, 0.645, 0.5072, 0.1236, 0.8021, 0.916 ]
115 | ]
116 | },
117 | {
118 | "name": "ceil",
119 | "inputs": [
120 | [ 0, 0.5, 1 ]
121 | ],
122 | "outputs": [
123 | [ 0, 1, 1 ]
124 | ]
125 | },
126 | {
127 | "name": "cmo",
128 | "inputs": [
129 | [ 101.0313, 101.0313, 101.125, 101.9687, 102.7813, 103, 102.9687, 103.0625, 102.9375, 102.7188, 102.75, 102.9063, 102.9687 ]
130 | ],
131 | "options": [ 10 ],
132 | "outputs": [
133 | [ 69.62, 71.4286, 71.0839 ]
134 | ]
135 | },
136 | {
137 | "name": "cos",
138 | "inputs": [
139 | [ 0, 0.5, 1 ]
140 | ],
141 | "outputs": [
142 | [ 1, 0.878, 0.540 ]
143 | ]
144 | },
145 | {
146 | "name": "cosh",
147 | "inputs": [
148 | [ 0, 0.5, 1 ]
149 | ],
150 | "outputs": [
151 | [ 1, 1.128, 1.543 ]
152 | ]
153 | },
154 | {
155 | "name": "crossany",
156 | "inputs": [
157 | [ 4, 4, 6, 6, 6, 4, 4, 6, 5, 5, 5 ],
158 | [ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 ]
159 | ],
160 | "outputs": [
161 | [ 0, 1, 0, 0, 1, 0, 1, 0, 0, 0 ]
162 | ]
163 | },
164 | {
165 | "name": "crossover",
166 | "inputs": [
167 | [ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 ],
168 | [ 4, 4, 6, 6, 6, 4, 4, 6, 5, 5, 5 ]
169 | ],
170 | "outputs": [
171 | [ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ]
172 | ]
173 | },
174 | {
175 | "name": "decay",
176 | "inputs": [
177 | [ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0 ]
178 | ],
179 | "options": [ 5 ],
180 | "outputs": [
181 | [ 0, 0, 0, 0, 1, 0.8, 0.6, 0.4, 0.2, 0, 0, 1, 0.8 ]
182 | ]
183 | },
184 | {
185 | "name": "div",
186 | "inputs": [
187 | [ 1, 2, 7, 4 ],
188 | [ 2, 1, 4, 7 ]
189 | ],
190 | "outputs": [
191 | [ 0.5, 2, 1.75, 0.571 ]
192 | ]
193 | },
194 | {
195 | "name": "edecay",
196 | "inputs": [
197 | [ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0 ]
198 | ],
199 | "options": [ 5 ],
200 | "outputs": [
201 | [ 0, 0, 0, 0, 1, 0.8, 0.64, 0.512, 0.4096, 0.3277, 0.2621, 1, 0.8 ]
202 | ]
203 | },
204 | {
205 | "name": "exp",
206 | "inputs": [
207 | [ 0.5, 1, 10 ]
208 | ],
209 | "outputs": [
210 | [ 1.649, 2.718, 22026.466 ]
211 | ]
212 | },
213 | {
214 | "name": "floor",
215 | "inputs": [
216 | [ 0, 0.5, 1 ]
217 | ],
218 | "outputs": [
219 | [ 0, 0, 1 ]
220 | ]
221 | },
222 | {
223 | "name": "kama",
224 | "inputs": [
225 | [ 50.25, 50.55, 52.5, 54.5, 54.1, 54.12, 55.5, 50.2, 50.45, 50.24, 50.24, 55.12, 56.54, 56.12, 56.1, 54.12, 59.54, 54.52 ]
226 | ],
227 | "options": [ 4 ],
228 | "outputs": [
229 | [ 54.5, 54.3732, 54.2948, 54.6461, 53.827, 53.3374, 52.8621, 51.8722, 53.118, 54.4669, 55.0451, 55.4099, 55.3468, 55.7115, 55.6875 ]
230 | ]
231 | },
232 | {
233 | "name": "lag",
234 | "inputs": [
235 | [ 1, 2, 3, 4, 5 ]
236 | ],
237 | "options": [ 1 ],
238 | "outputs": [
239 | [ 1, 2, 3, 4 ]
240 | ]
241 | },
242 | {
243 | "name": "linreg",
244 | "inputs": [
245 | [ 10.5, 11.2, 10.3, 12.1, 11.2, 10.5, 11.1, 11.1, 10.2 ]
246 | ],
247 | "options": [ 5 ],
248 | "outputs": [
249 | [ 11.52, 10.96, 11.04, 10.78, 10.54 ]
250 | ]
251 | },
252 | {
253 | "name": "linregintercept",
254 | "inputs": [
255 | [ 10.5, 11.2, 10.3, 12.1, 11.2, 10.5, 11.1, 11.1, 10.2 ]
256 | ],
257 | "options": [ 5 ],
258 | "outputs": [
259 | [ 10.6, 11.16, 11.04, 11.62, 11.1 ]
260 | ]
261 | },
262 | {
263 | "name": "linregslope",
264 | "inputs": [
265 | [ 6, 7, 8, 9, 10, 11 ]
266 | ],
267 | "options": [ 5 ],
268 | "outputs": [
269 | [ 1, 1 ]
270 | ]
271 | },
272 | {
273 | "name": "ln",
274 | "inputs": [
275 | [ 0.5, 1, 10 ]
276 | ],
277 | "outputs": [
278 | [ -0.693, 0, 2.303 ]
279 | ]
280 | },
281 | {
282 | "name": "log10",
283 | "inputs": [
284 | [ 0.5, 1, 10 ]
285 | ],
286 | "outputs": [
287 | [ -0.301, 0, 1 ]
288 | ]
289 | },
290 | {
291 | "name": "marketfi",
292 | "inputs": [
293 | [ 86, 88, 92, 90, 91, 102 ],
294 | [ 70, 85, 82, 81, 90, 95 ],
295 | [ 2500, 3521, 2541, 4582, 5214, 2541 ]
296 | ],
297 | "outputs": [
298 | [ 0.0064, 0.0009, 0.0039, 0.0020, 0.0002, 0.0028 ]
299 | ]
300 | },
301 | {
302 | "name": "max",
303 | "inputs": [
304 | [ 1, 6, 4, 9, 2, 3, 4 ]
305 | ],
306 | "options": [ 3 ],
307 | "outputs": [
308 | [ 6, 9, 9, 9, 4 ]
309 | ]
310 | },
311 | {
312 | "name": "md",
313 | "inputs": [
314 | [ 1, 2, 3, 4, 5, 17 ]
315 | ],
316 | "options": [ 3 ],
317 | "outputs": [
318 | [ 0.6666, 0.6666, 0.6666, 5.5555 ]
319 | ]
320 | },
321 | {
322 | "name": "min",
323 | "inputs": [
324 | [ 1, 5, 7, 9, 2, 3, 4 ]
325 | ],
326 | "options": [ 3 ],
327 | "outputs": [
328 | [ 1, 5, 2, 2, 2 ]
329 | ]
330 | },
331 | {
332 | "name": "mul",
333 | "inputs": [
334 | [ 1, 2, 7, 4 ],
335 | [ 2, 1, 4, 7 ]
336 | ],
337 | "outputs": [
338 | [ 2, 2, 28, 28 ]
339 | ]
340 | },
341 | {
342 | "name": "mom",
343 | "inputs": [
344 | [ 1, 7, 12, 4, 5, 8, 11, 2, 9 ]
345 | ],
346 | "options": [ 3 ],
347 | "outputs": [
348 | [ 3, -2, -4, 7, -3, 1 ]
349 | ]
350 | },
351 | {
352 | "name": "natr",
353 | "inputs": [
354 | [ 12.3125, 12.25, 12.3125, 12.2812, 12.375, 12.375, 12.3125, 12.375, 12.5, 12.5938, 12.3438, 12.4062, 12.375, 12.4062, 12.375, 12.2812, 12.25, 12.0625, 12.3125, 12.3125 ],
355 | [ 12.1875, 12.1562, 12.1875, 12.125, 12.125, 12.2812, 12.1875, 12.1875, 12.2812, 12.3125, 12.2812, 12.2812, 12.2812, 12.2812, 11.9688, 12.0938, 12, 11.6562, 12.1562, 12.125 ],
356 | [ 12.25, 12.1875, 12.25, 12.1875, 12.375, 12.3125, 12.2188, 12.3438, 12.5, 12.375, 12.3438, 12.3438, 12.2812, 12.375, 12.0938, 12.1562, 12.0625, 11.9688, 12.1875, 12.1562 ]
357 | ],
358 | "options": [ 4 ],
359 | "outputs": [
360 | [ 1.0256, 1.2630, 1.1419, 1.1188, 1.2103, 1.3344, 1.5790, 1.3772, 1.2857, 1.1603, 1.1160, 1.6967, 1.6510, 1.7658, 2.1840, 2.3130, 2.1248 ]
361 | ]
362 | },
363 | {
364 | "name": "ppo",
365 | "inputs": [
366 | [ 25, 24.875, 24.781, 24.594, 24.5, 24.625, 25.219, 27.25 ]
367 | ],
368 | "options": [ 3, 5 ],
369 | "outputs": [
370 | [ -0.0835, -0.1605, -0.2857, -0.3441, -0.2218, 0.2554, 1.6793 ]
371 | ]
372 | },
373 | {
374 | "name": "pvi",
375 | "inputs": [
376 | [ 6.5313, 6.5625, 6.4688, 6.4375, 6.2188, 6.25, 6.125, 6.1563, 6.25, 6.3125, 6.4688, 6.2813, 6.125, 6.1875, 6.1563, 6.2813, 6.2188, 6.1563, 6.1875, 6.375, 6.2813, 6.2813 ],
377 | [ 10500, 6492, 6540, 8924, 5416, 4588, 16236, 2864, 3080, 5312, 12456, 3020, 12228, 5248, 6632, 4104, 4464, 6212, 3836, 7640, 3544, 4660 ]
378 | ],
379 | "outputs": [
380 | [ 1000, 1000, 985.7219048, 980.952381, 980.952381, 980.952381, 961.3333333, 961.3333333, 975.9650006, 985.7246506, 1010.131583, 1010.131583, 984.9960913, 984.9960913, 980.0293231, 980.0293231, 970.2778652, 960.5264072, 960.5264072, 989.6332681, 989.6332681, 989.6332681 ]
381 | ]
382 | },
383 | {
384 | "name": "roc",
385 | "inputs": [
386 | [ 5.5625, 5.375, 5.375, 5.0625, 5.1094, 5.1094, 5.0938, 5 ]
387 | ],
388 | "options": [ 3 ],
389 | "outputs": [
390 | [ -0.08989, -0.04941, -0.04941, 0.00618, -0.02141 ]
391 | ]
392 | },
393 | {
394 | "name": "round",
395 | "inputs": [
396 | [ 0, -0.5, -1.1, -1.6, 1.5, 1.4, 1.6 ]
397 | ],
398 | "outputs": [
399 | [ 0, 0, -1, -2, 2, 1, 2 ]
400 | ]
401 | },
402 | {
403 | "name": "sin",
404 | "inputs": [
405 | [ 0, 0.5, 1 ]
406 | ],
407 | "outputs": [
408 | [ 0, 0.479, 0.841 ]
409 | ]
410 | },
411 | {
412 | "name": "sinh",
413 | "inputs": [
414 | [ 0, 0.5, 1 ]
415 | ],
416 | "outputs": [
417 | [ 0, 0.521, 1.175 ]
418 | ]
419 | },
420 | {
421 | "name": "sqrt",
422 | "inputs": [
423 | [ 1, 4, 25, 144 ]
424 | ],
425 | "outputs": [
426 | [ 1, 2, 5, 12 ]
427 | ]
428 | },
429 | {
430 | "name": "stddev",
431 | "inputs": [
432 | [ 100, 101, 102, 107, 115, 123, 100, 92, 99, 58, 150 ]
433 | ],
434 | "options": [ 3 ],
435 | "outputs": [
436 | [ 0.816496581, 2.624669291, 5.354126135, 6.531972647, 9.533566431, 13.1402689, 3.559026084, 17.90716802, 37.63272807 ]
437 | ]
438 | },
439 | {
440 | "name": "stderr",
441 | "inputs": [
442 | [ 100, 101, 102, 107, 115, 123, 100, 92, 99, 58, 150 ]
443 | ],
444 | "options": [ 3 ],
445 | "outputs": [
446 | [ 0.4714, 1.5154, 3.0912, 3.7712, 5.5042, 7.5865, 2.0548, 10.3387, 21.7273 ]
447 | ]
448 | },
449 | {
450 | "name": "stochrsi",
451 | "inputs": [
452 | [ 37.875, 39.5, 38.75, 39.8125, 40, 39.875, 40.1875, 41.25, 41.125, 41.625, 41.25, 40.1875, 39.9375, 39.9375, 40.5, 41.9375, 42.25, 42.25, 41.875, 41.875 ]
453 | ],
454 | "options": [ 5 ],
455 | "outputs": [
456 | [ 0.9613, 0, 0, 0, 0, 0.46, 1, 1, 1, 0.3751, 0 ]
457 | ]
458 | },
459 | {
460 | "name": "sub",
461 | "inputs": [
462 | [ 1, 2, 7, 4 ],
463 | [ 2, 1, 4, 7 ]
464 | ],
465 | "outputs": [
466 | [ -1, 1, 3, -3 ]
467 | ]
468 | },
469 | {
470 | "name": "sum",
471 | "inputs": [
472 | [ 1, 2, 3, 4, 5, 7, 8 ]
473 | ],
474 | "options": [ 2 ],
475 | "outputs": [
476 | [ 3, 5, 7, 9, 12, 15 ]
477 | ]
478 | },
479 | {
480 | "name": "tan",
481 | "inputs": [
482 | [ 0, 0.5, 1 ]
483 | ],
484 | "outputs": [
485 | [ 0, 0.546, 1.557 ]
486 | ]
487 | },
488 | {
489 | "name": "tanh",
490 | "inputs": [
491 | [ 0, 0.5, 1 ]
492 | ],
493 | "outputs": [
494 | [ 0, 0.462, 0.762 ]
495 | ]
496 | },
497 | {
498 | "name": "todeg",
499 | "inputs": [
500 | [ 0, 1, 2, 3.14159, -1 ]
501 | ],
502 | "outputs": [
503 | [ 0, 57.296, 114.592, 180, -57.296 ]
504 | ]
505 | },
506 | {
507 | "name": "torad",
508 | "inputs": [
509 | [ 0, 90, 180, 360, -90 ]
510 | ],
511 | "outputs": [
512 | [ 0, 1.571, 3.142, 6.283, -1.571 ]
513 | ]
514 | },
515 | {
516 | "name": "trunc",
517 | "inputs": [
518 | [ 0, -0.5, -1.1, -1.6, 1.5, 1.4, 1.6 ]
519 | ],
520 | "outputs": [
521 | [ 0, 0, -1, -1, 1, 1, 1 ]
522 | ]
523 | },
524 | {
525 | "name": "tsf",
526 | "inputs": [
527 | [ 10.5, 11.2, 10.3, 12.1, 11.2, 10.5, 11.1, 11.1, 10.2 ]
528 | ],
529 | "options": [ 5 ],
530 | "outputs": [
531 | [ 11.75, 10.91, 11.04, 10.57, 10.4 ]
532 | ]
533 | },
534 | {
535 | "name": "var",
536 | "inputs": [
537 | [ 100, 101, 102, 107, 115, 123, 100, 92, 99, 58, 150 ]
538 | ],
539 | "options": [ 3 ],
540 | "outputs": [
541 | [ 0.666666667, 6.888888889, 28.66666667, 42.66666667, 90.88888889, 172.6666667, 12.66666667, 320.6666667, 1416.222222 ]
542 | ]
543 | },
544 | {
545 | "name": "vidya",
546 | "inputs": [
547 | [ 50.25, 50.55, 52.5, 54.5, 54.1, 54.12, 55.5, 50.2, 50.45, 50.24, 50.24, 55.12, 56.54, 56.12, 56.1, 54.12, 59.54, 54.52 ]
548 | ],
549 | "options": [ 3, 6, 0.2 ],
550 | "outputs": [
551 | [ 54.1000, 54.1004, 54.2148, 53.1633, 52.5165, 52.4937, 52.4732, 52.9862, 53.7103, 53.8114, 53.8453, 53.8693, 55.3888, 55.1443 ]
552 | ]
553 | },
554 | {
555 | "name": "volatility",
556 | "inputs": [
557 | [ 100, 101, 102, 107, 115, 123, 100, 92, 99, 58, 150 ]
558 | ],
559 | "options": [ 3 ],
560 | "outputs": [
561 | [ 0.292367173, 0.423342593, 0.176459427, 1.939651221, 1.670293237, 1.714813191, 3.246143771, 13.51373467 ]
562 | ]
563 | },
564 | {
565 | "name": "vwma",
566 | "inputs": [
567 | [ 50.25, 50.55, 52.5, 54.5, 54.1, 54.12, 55.5, 50.2, 50.45, 50.24 ],
568 | [ 12412, 12458, 15874, 12354, 12456, 12542, 15421, 19510, 12521, 12041 ]
569 | ],
570 | "options": [ 4 ],
571 | "outputs": [
572 | [ 51.9819, 52.8828, 53.7204, 54.6075, 53.1948, 52.4340, 51.6345 ]
573 | ]
574 | },
575 | {
576 | "name": "zlema",
577 | "inputs": [
578 | [ 50.25, 50.55, 52.5, 54.5, 54.1, 54.12, 55.5, 50.2, 50.45, 50.24, 50.24, 55.12, 56.54, 56.12, 56.1, 54.12, 59.54, 54.52 ]
579 | ],
580 | "options": [ 6 ],
581 | "outputs": [
582 | [ 50.55, 51.7500, 53.6643, 54.2459, 54.1014, 54.9010, 52.4378, 50.4270, 50.3850, 50.2836, 53.0597, 55.8541, 56.2158, 56.0570, 54.9321, 57.2315, 56.5711 ]
583 | ]
584 | }
585 | ]
586 | }
587 |
--------------------------------------------------------------------------------
/tests/Tulip.NETCore.Tests/DataSets/testdata.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$id": "https://github.com/hmG3/Tulip.NETCore/testdata.schema.json",
3 | "$schema": "http://json-schema.org/draft-07/schema#",
4 | "title": "JSON Schema for data used in unit tests",
5 | "type": "object",
6 | "properties": {
7 | "data": {
8 | "type": "array",
9 | "items": {
10 | "type": "object",
11 | "properties": {
12 | "name": {
13 | "type": "string",
14 | "description": "Unique name of an indicator."
15 | },
16 | "inputs": {
17 | "type": "array",
18 | "description": "An array of input values.",
19 | "minItems": 1,
20 | "items": {
21 | "type": "array",
22 | "items": {
23 | "type": "number"
24 | }
25 | }
26 | },
27 | "options": {
28 | "type": "array",
29 | "description": "An array of options.",
30 | "items": {
31 | "type": "number"
32 | }
33 | },
34 | "outputs": {
35 | "type": "array",
36 | "description": "An array of output value.",
37 | "minItems": 1,
38 | "items": {
39 | "type": "array",
40 | "items": {
41 | "type": "number"
42 | }
43 | }
44 | },
45 | "skip": {
46 | "type": "boolean",
47 | "description": "Flag indicates to skip test."
48 | }
49 | },
50 | "additionalProperties": false
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/tests/Tulip.NETCore.Tests/Indicator_Tests.cs:
--------------------------------------------------------------------------------
1 | using Shouldly;
2 | using Tulip.NETCore.Tests.Models;
3 | using Xunit;
4 |
5 | namespace Tulip.NETCore.Tests;
6 |
7 | public sealed class Indicator_Tests
8 | {
9 | [SkippableTheory]
10 | [JsonFileData("DataSets/untest.json", typeof(double), "_")]
11 | [JsonFileData("DataSets/atoz.json", typeof(double), "_")]
12 | [JsonFileData("DataSets/extra.json", typeof(double), "_")]
13 | #pragma warning disable xUnit1026
14 | public void Should_Calculate_CorrectOutput_With_OKStatus_For_DoubleInput(TestDataModel model, string fileName)
15 | #pragma warning restore xUnit1026
16 | {
17 | Skip.If(model.Skip, "Test marked as skipped in the dataset.");
18 |
19 | const double equalityTolerance = 0.001d;
20 |
21 | Indicators.IndicatorsDefinition.ShouldContainKey(model.Name, $"Cannot find definition for '{model.Name}");
22 | var indicator = Indicators.IndicatorsDefinition[model.Name];
23 |
24 | model.Options.Length.ShouldBe(indicator.Options.Length, "Number of options must match the definition");
25 | var inputOffset = indicator.Start(model.Options);
26 | model.Inputs.Length.ShouldBe(indicator.Inputs.Length, "Number of inputs must match the definition");
27 | var outputLength = model.Inputs[0].Length - inputOffset;
28 | outputLength.ShouldBePositive("Output array should have the correct length");
29 |
30 | var resultOutput = new double[model.Outputs.Length][];
31 | resultOutput.Length.ShouldBe(indicator.Outputs.Length, "Number of outputs must match the definition");
32 | for (var i = 0; i < resultOutput.Length; i++)
33 | {
34 | resultOutput[i] = new double[outputLength];
35 | }
36 |
37 | var returnCode = indicator.Run(model.Inputs, model.Options, resultOutput);
38 | returnCode.ShouldBe(0, "Indicator should complete with success status code TI_OK(0)");
39 |
40 | for (var i = 0; i < resultOutput.Length; i++)
41 | {
42 | resultOutput[i].Length.ShouldBe(model.Outputs[i].Length,
43 | $"Expected and calculated length of the output values should be equal for output {i + 1}");
44 | resultOutput[i].ShouldBe(model.Outputs[i], equalityTolerance,
45 | $"Calculated values should be within expected for output {i + 1}");
46 | }
47 | }
48 |
49 | [SkippableTheory]
50 | [JsonFileData("DataSets/untest.json", typeof(float), "_")]
51 | [JsonFileData("DataSets/atoz.json", typeof(float), "_")]
52 | [JsonFileData("DataSets/extra.json", typeof(float), "_")]
53 | #pragma warning disable xUnit1026
54 | public void Should_Calculate_CorrectOutput_With_OKStatus_For_FloatInput(TestDataModel model, string fileName)
55 | #pragma warning restore xUnit1026
56 | {
57 | Skip.If(model.Skip, "Test marked as skipped in the dataset.");
58 | Skip.If((fileName == "untest.json" && model.Name is "ad" or "adosc") || model.Name is "kvo",
59 | "The precision of floating-point arithmetic is insufficient for calculating accurate results.");
60 |
61 | const float equalityTolerance = 0.1f;
62 |
63 | Indicators.IndicatorsDefinition.ShouldContainKey(model.Name, $"Cannot find definition for '{model.Name}");
64 | var indicator = Indicators.IndicatorsDefinition[model.Name];
65 |
66 | model.Options.Length.ShouldBe(indicator.Options.Length, "Number of options must match the definition");
67 | var inputOffset = indicator.Start(model.Options);
68 | model.Inputs.Length.ShouldBe(indicator.Inputs.Length, "Number of inputs must match the definition");
69 | var outputLength = model.Inputs[0].Length - inputOffset;
70 | outputLength.ShouldBePositive("Output array should have the correct length");
71 |
72 | var resultOutput = new float[model.Outputs.Length][];
73 | resultOutput.Length.ShouldBe(indicator.Outputs.Length, "Number of outputs must match the definition");
74 | for (var i = 0; i < resultOutput.Length; i++)
75 | {
76 | resultOutput[i] = new float[outputLength];
77 | }
78 |
79 | var returnCode = indicator.Run(model.Inputs, model.Options, resultOutput);
80 | returnCode.ShouldBe(0, "Indicator should complete with success status code TI_OK(0)");
81 |
82 | for (var i = 0; i < resultOutput.Length; i++)
83 | {
84 | resultOutput[i].Length.ShouldBe(model.Outputs[i].Length,
85 | $"Expected and calculated length of the output values should be equal for output {i + 1}");
86 | resultOutput[i].ShouldBe(model.Outputs[i], equalityTolerance,
87 | $"Calculated values should be within expected for output {i + 1}");
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/tests/Tulip.NETCore.Tests/JsonFileDataAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Reflection;
5 | using System.Text.Json;
6 | using Tulip.NETCore.Tests.Models;
7 | using Xunit.Sdk;
8 |
9 | namespace Tulip.NETCore.Tests;
10 |
11 | public sealed class JsonFileDataAttribute : DataAttribute
12 | {
13 | private readonly string _filePath;
14 | private readonly Type _targetCollectionType;
15 | private readonly string? _propertyName;
16 |
17 | ///
18 | /// Load data from a JSON file as the data source for a theory
19 | ///
20 | /// The absolute or relative path to the JSON file to load
21 | /// The type of values for the test model
22 | /// The name of the property on the JSON file that contains the data for the test
23 | public JsonFileDataAttribute(string filePath, Type targetModelType, string? propertyName = null)
24 | {
25 | _filePath = filePath;
26 | _targetCollectionType = typeof(IEnumerable<>).MakeGenericType(typeof(TestDataModel<>).MakeGenericType(targetModelType));
27 | _propertyName = propertyName;
28 | }
29 |
30 | ///
31 | public override IEnumerable