Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 806ae22abe | |||
| fb9c39d4cd | |||
| b1653e2107 | |||
| 32e18cb3a3 | |||
| dc0c3d1736 | |||
| ad1231cde1 | |||
| 7ebb60b60a | |||
| d7cb771a28 | |||
| 3e5a19c94a | |||
| 8bfe24ac1d |
@@ -926,6 +926,16 @@ jobs:
|
||||
R CMD INSTALL bindings/r
|
||||
Rscript -e 'library(testthat); library(wickra); test_dir("bindings/r/tests/testthat", stop_on_failure = TRUE)'
|
||||
|
||||
- name: Build the vignette code
|
||||
shell: bash
|
||||
# The getting-started vignette runs at R CMD check time on r-universe /
|
||||
# CRAN (with pandoc); this job only INSTALLs, so execute the vignette's R
|
||||
# chunks here (knit, no pandoc needed) to catch a broken example before it
|
||||
# reaches the published build.
|
||||
run: |
|
||||
Rscript -e 'install.packages("knitr", repos = Sys.getenv("RSPM", unset = "https://cloud.r-project.org"))'
|
||||
Rscript -e 'knitr::knit("bindings/r/vignettes/getting-started.Rmd", output = tempfile(fileext = ".md"), quiet = TRUE); cat("vignette code OK\n")'
|
||||
|
||||
- name: Run the offline R examples
|
||||
shell: bash
|
||||
# No loader-path exports: the installed package is self-contained (bundled
|
||||
|
||||
+35
-1
@@ -7,6 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.8.8] - 2026-06-11
|
||||
### Fixed
|
||||
- R binding: declare `Depends: R (>= 2.10)`, clearing the `R CMD check` warning
|
||||
("package needs dependence on R (>= 2.10)") that the bundled, lazy-loaded
|
||||
`sample_ohlcv` dataset triggers on r-universe / CRAN.
|
||||
|
||||
## [0.8.7] - 2026-06-11
|
||||
### Added
|
||||
- R binding: a *Getting started* vignette and a synthetic `sample_ohlcv` example
|
||||
dataset, giving new users a runnable, self-contained walkthrough and populating
|
||||
the R-universe Articles and Datasets tabs. The vignette's code is exercised in
|
||||
CI so a broken example is caught before the published build.
|
||||
|
||||
## [0.8.6] - 2026-06-11
|
||||
### Changed
|
||||
- Package registry metadata for better discoverability:
|
||||
- R (R-universe): added the R-universe URL and `X-schema.org-keywords` to the
|
||||
R `DESCRIPTION`, plus a package logo at `bindings/r/man/figures/logo.png`
|
||||
(pkgdown convention).
|
||||
- Python (PyPI): added a `Documentation` project URL.
|
||||
- C# (NuGet): added a package icon via `PackageIcon`.
|
||||
|
||||
## [0.8.5] - 2026-06-11
|
||||
### Fixed
|
||||
- The R binding's golden-fixture parity test now skips gracefully when the shared
|
||||
`testdata/golden` fixtures are not bundled with the package — standalone
|
||||
r-universe / CRAN builds package only `bindings/r`, so the repo-root fixtures
|
||||
are unreachable there. The parity stays enforced by the repository CI, where
|
||||
the fixtures are present.
|
||||
|
||||
## [0.8.4] - 2026-06-11
|
||||
### Fixed
|
||||
- A single non-finite (NaN/inf) tick no longer poisons indicator state.
|
||||
@@ -1542,7 +1572,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
optional Binance live feed.
|
||||
- Bindings for Python, Node.js, and WebAssembly.
|
||||
|
||||
[Unreleased]: https://github.com/wickra-lib/wickra/compare/v0.8.4...HEAD
|
||||
[Unreleased]: https://github.com/wickra-lib/wickra/compare/v0.8.8...HEAD
|
||||
[0.8.8]: https://github.com/wickra-lib/wickra/compare/v0.8.7...v0.8.8
|
||||
[0.8.7]: https://github.com/wickra-lib/wickra/compare/v0.8.6...v0.8.7
|
||||
[0.8.6]: https://github.com/wickra-lib/wickra/compare/v0.8.5...v0.8.6
|
||||
[0.8.5]: https://github.com/wickra-lib/wickra/compare/v0.8.4...v0.8.5
|
||||
[0.8.4]: https://github.com/wickra-lib/wickra/compare/v0.8.3...v0.8.4
|
||||
[0.8.3]: https://github.com/wickra-lib/wickra/compare/v0.8.2...v0.8.3
|
||||
[0.8.2]: https://github.com/wickra-lib/wickra/compare/v0.8.1...v0.8.2
|
||||
|
||||
Generated
+9
-9
@@ -1944,7 +1944,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra"
|
||||
version = "0.8.4"
|
||||
version = "0.8.8"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"criterion",
|
||||
@@ -1955,7 +1955,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-bench"
|
||||
version = "0.8.4"
|
||||
version = "0.8.8"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"kand",
|
||||
@@ -1967,14 +1967,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-c"
|
||||
version = "0.8.4"
|
||||
version = "0.8.8"
|
||||
dependencies = [
|
||||
"wickra-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wickra-core"
|
||||
version = "0.8.4"
|
||||
version = "0.8.8"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"proptest",
|
||||
@@ -1984,7 +1984,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-data"
|
||||
version = "0.8.4"
|
||||
version = "0.8.8"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"csv",
|
||||
@@ -2001,7 +2001,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-examples"
|
||||
version = "0.8.4"
|
||||
version = "0.8.8"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
"tokio",
|
||||
@@ -2011,7 +2011,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-node"
|
||||
version = "0.8.4"
|
||||
version = "0.8.8"
|
||||
dependencies = [
|
||||
"napi",
|
||||
"napi-build",
|
||||
@@ -2021,7 +2021,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-python"
|
||||
version = "0.8.4"
|
||||
version = "0.8.8"
|
||||
dependencies = [
|
||||
"numpy",
|
||||
"pyo3",
|
||||
@@ -2030,7 +2030,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-wasm"
|
||||
version = "0.8.4"
|
||||
version = "0.8.8"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"js-sys",
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ members = [
|
||||
exclude = ["fuzz"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.8.4"
|
||||
version = "0.8.8"
|
||||
authors = ["kingchenc <support@wickra.org>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.86"
|
||||
@@ -26,7 +26,7 @@ keywords = ["finance", "trading", "indicators", "technical-analysis", "ta"]
|
||||
categories = ["finance", "mathematics", "science"]
|
||||
|
||||
[workspace.dependencies]
|
||||
wickra-core = { path = "crates/wickra-core", version = "0.8.4" }
|
||||
wickra-core = { path = "crates/wickra-core", version = "0.8.8" }
|
||||
|
||||
thiserror = "2"
|
||||
rayon = "1.10"
|
||||
|
||||
@@ -358,6 +358,12 @@ Every layer is covered; run the suites with the commands in
|
||||
- `bindings/java`: JUnit cases covering one indicator per FFI archetype
|
||||
(scalar/batch, multi-output, bars, profile, array input) plus batch equivalence.
|
||||
|
||||
The four C-ABI bindings (C#, Go, Java, R) additionally replay a shared,
|
||||
language-neutral golden fixture (`testdata/golden/*.csv`, generated by
|
||||
`cargo run -p wickra-examples --bin gen_golden`) and assert exact parity with the
|
||||
Rust reference outputs across every archetype (SMA, EMA, RSI, ATR, MACD, ADX,
|
||||
Beta), catching FFI wiring bugs the math-only core tests cannot see.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are very welcome — issues, bug reports, ideas, and pull requests
|
||||
@@ -413,13 +419,13 @@ The library is provided **as is**, without warranty of any kind; see
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/wickra-lib/wickra/stargazers">
|
||||
<img alt="GitHub stars" src="https://img.shields.io/github/stars/wickra-lib/wickra?style=for-the-badge&logo=github&logoColor=white&color=ffd866">
|
||||
<img alt="GitHub stars" src="https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/stars.svg">
|
||||
</a>
|
||||
<a href="https://github.com/wickra-lib/wickra/network/members">
|
||||
<img alt="GitHub forks" src="https://img.shields.io/github/forks/wickra-lib/wickra?style=for-the-badge&logo=github&logoColor=white&color=78dce8">
|
||||
<img alt="GitHub forks" src="https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/forks.svg">
|
||||
</a>
|
||||
<a href="https://github.com/wickra-lib/wickra/issues">
|
||||
<img alt="GitHub issues" src="https://img.shields.io/github/issues/wickra-lib/wickra?style=for-the-badge&logo=github&logoColor=white&color=ff6188">
|
||||
<img alt="GitHub issues" src="https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/issues.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -430,6 +436,6 @@ The library is provided **as is**, without warranty of any kind; see
|
||||
<p align="center">
|
||||
<a href="https://star-history.com/#wickra-lib/wickra&Date">
|
||||
<img alt="Wickra star history" width="640"
|
||||
src="https://api.star-history.com/svg?repos=wickra-lib/wickra&type=Date&theme=dark">
|
||||
src="https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/star-history.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
+3
-3
@@ -2,13 +2,13 @@
|
||||
|
||||
## Supported versions
|
||||
|
||||
Wickra is pre-1.0. Security fixes are applied to the latest released `0.8.4`
|
||||
Wickra is pre-1.0. Security fixes are applied to the latest released `0.8.8`
|
||||
version only; please upgrade to the newest release before reporting an issue.
|
||||
|
||||
| Version | Supported |
|
||||
| --- | --- |
|
||||
| 0.8.4 (latest) | :white_check_mark: |
|
||||
| < 0.8.4 | :x: |
|
||||
| 0.8.8 (latest) | :white_check_mark: |
|
||||
| < 0.8.8 | :x: |
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Wickra;
|
||||
using Xunit;
|
||||
|
||||
namespace Wickra.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Golden-fixture parity: replay the shared <c>testdata/golden</c> input series
|
||||
/// through the C# FFI and assert every value matches the Rust reference output.
|
||||
/// Where the archetype tests only check finiteness, this pins exact values, so a
|
||||
/// wiring bug (swapped parameter, wrong multi-output field) is caught.
|
||||
/// Fixtures are generated by <c>cargo run -p wickra-examples --bin gen_golden</c>.
|
||||
/// </summary>
|
||||
public class GoldenTests
|
||||
{
|
||||
private const double Tol = 1e-6;
|
||||
|
||||
private static string GoldenDir([CallerFilePath] string file = "") =>
|
||||
Path.GetFullPath(Path.Combine(Path.GetDirectoryName(file)!, "..", "..", "..", "testdata", "golden"));
|
||||
|
||||
private static List<string[]> ReadCsv(string name)
|
||||
{
|
||||
var path = Path.Combine(GoldenDir(), name + ".csv");
|
||||
return File.ReadAllLines(path)
|
||||
.Skip(1) // header
|
||||
.Where(l => l.Length > 0)
|
||||
.Select(l => l.Split(','))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static double[][] Input()
|
||||
{
|
||||
return ReadCsv("input")
|
||||
.Select(r => r.Select(c => double.Parse(c, CultureInfo.InvariantCulture)).ToArray())
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static double Cell(string s) =>
|
||||
s == "nan" ? double.NaN : double.Parse(s, CultureInfo.InvariantCulture);
|
||||
|
||||
private static void AssertClose(double got, double want, int row, string field)
|
||||
{
|
||||
if (double.IsNaN(want))
|
||||
{
|
||||
Assert.True(double.IsNaN(got), $"row {row} {field}: expected warmup/NaN, got {got}");
|
||||
return;
|
||||
}
|
||||
var tol = Tol * Math.Max(1.0, Math.Abs(want));
|
||||
Assert.True(Math.Abs(got - want) <= tol, $"row {row} {field}: got {got}, want {want}");
|
||||
}
|
||||
|
||||
// --- scalar (close-driven) ------------------------------------------------
|
||||
|
||||
[Theory]
|
||||
[InlineData("sma")]
|
||||
[InlineData("ema")]
|
||||
[InlineData("rsi")]
|
||||
public void Scalar_MatchesGolden(string name)
|
||||
{
|
||||
var input = Input();
|
||||
var expected = ReadCsv(name);
|
||||
using var ind = (IDisposable)(name switch
|
||||
{
|
||||
"sma" => new Sma(14),
|
||||
"ema" => new Ema(14),
|
||||
"rsi" => new Rsi(14),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(name)),
|
||||
});
|
||||
for (var i = 0; i < input.Length; i++)
|
||||
{
|
||||
var close = input[i][3];
|
||||
double got = ind switch
|
||||
{
|
||||
Sma s => s.Update(close),
|
||||
Ema e => e.Update(close),
|
||||
Rsi r => r.Update(close),
|
||||
_ => double.NaN,
|
||||
};
|
||||
AssertClose(got, Cell(expected[i][0]), i, name);
|
||||
}
|
||||
}
|
||||
|
||||
// --- candle, single output ------------------------------------------------
|
||||
|
||||
[Fact]
|
||||
public void Candle_Atr_MatchesGolden()
|
||||
{
|
||||
var input = Input();
|
||||
var expected = ReadCsv("atr");
|
||||
using var atr = new Atr(14);
|
||||
for (var i = 0; i < input.Length; i++)
|
||||
{
|
||||
var (o, h, l, c, v) = (input[i][0], input[i][1], input[i][2], input[i][3], input[i][4]);
|
||||
AssertClose(atr.Update(o, h, l, c, v, i), Cell(expected[i][0]), i, "atr");
|
||||
}
|
||||
}
|
||||
|
||||
// --- pairwise -------------------------------------------------------------
|
||||
|
||||
[Fact]
|
||||
public void Pairwise_Beta_MatchesGolden()
|
||||
{
|
||||
var input = Input();
|
||||
var expected = ReadCsv("beta");
|
||||
using var beta = new Beta(20);
|
||||
for (var i = 0; i < input.Length; i++)
|
||||
{
|
||||
// generator fed (close, open)
|
||||
AssertClose(beta.Update(input[i][3], input[i][0]), Cell(expected[i][0]), i, "beta");
|
||||
}
|
||||
}
|
||||
|
||||
// --- scalar multi-output: MACD -------------------------------------------
|
||||
|
||||
[Fact]
|
||||
public void MultiOutput_Macd_MatchesGolden()
|
||||
{
|
||||
var input = Input();
|
||||
var expected = ReadCsv("macd");
|
||||
using var macd = new MacdIndicator(12, 26, 9);
|
||||
for (var i = 0; i < input.Length; i++)
|
||||
{
|
||||
MacdOutput? got = macd.Update(input[i][3]);
|
||||
var e = expected[i];
|
||||
if (e[0] == "nan")
|
||||
{
|
||||
Assert.Null(got);
|
||||
continue;
|
||||
}
|
||||
Assert.NotNull(got);
|
||||
AssertClose(got!.Value.Macd, Cell(e[0]), i, "macd.macd");
|
||||
AssertClose(got.Value.Signal, Cell(e[1]), i, "macd.signal");
|
||||
AssertClose(got.Value.Histogram, Cell(e[2]), i, "macd.histogram");
|
||||
}
|
||||
}
|
||||
|
||||
// --- candle multi-output: ADX --------------------------------------------
|
||||
|
||||
[Fact]
|
||||
public void MultiOutput_Adx_MatchesGolden()
|
||||
{
|
||||
var input = Input();
|
||||
var expected = ReadCsv("adx");
|
||||
using var adx = new Adx(14);
|
||||
for (var i = 0; i < input.Length; i++)
|
||||
{
|
||||
var (o, h, l, c, v) = (input[i][0], input[i][1], input[i][2], input[i][3], input[i][4]);
|
||||
AdxOutput? got = adx.Update(o, h, l, c, v, i);
|
||||
var e = expected[i];
|
||||
if (e[0] == "nan")
|
||||
{
|
||||
Assert.Null(got);
|
||||
continue;
|
||||
}
|
||||
Assert.NotNull(got);
|
||||
AssertClose(got!.Value.PlusDi, Cell(e[0]), i, "adx.plus_di");
|
||||
AssertClose(got.Value.MinusDi, Cell(e[1]), i, "adx.minus_di");
|
||||
AssertClose(got.Value.Adx, Cell(e[2]), i, "adx.adx");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<!-- NuGet package metadata -->
|
||||
<PackageId>Wickra</PackageId>
|
||||
<Version>0.8.4</Version>
|
||||
<Version>0.8.8</Version>
|
||||
<Authors>kingchenc</Authors>
|
||||
<Description>High-performance streaming technical-analysis indicators (514 indicators) for .NET, backed by the native Rust core via the Wickra C ABI.</Description>
|
||||
<PackageLicenseExpression>MIT OR Apache-2.0</PackageLicenseExpression>
|
||||
@@ -20,6 +20,7 @@
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>technical-analysis;indicators;trading;finance;streaming;ffi;native</PackageTags>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
@@ -42,6 +43,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\README.md" Pack="true" PackagePath="\" />
|
||||
<None Include="..\icon.png" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -0,0 +1,191 @@
|
||||
package wickra
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Golden-fixture parity: replay the shared testdata/golden input series through
|
||||
// the Go FFI and assert every value matches the Rust reference output. Where the
|
||||
// archetype test only checks finiteness, this pins exact values, catching wiring
|
||||
// bugs (swapped params, wrong multi-output field). Fixtures are generated by
|
||||
// `cargo run -p wickra-examples --bin gen_golden`.
|
||||
|
||||
const goldenTol = 1e-6
|
||||
|
||||
func readGolden(t *testing.T, name string) [][]string {
|
||||
t.Helper()
|
||||
f, err := os.Open("../../testdata/golden/" + name + ".csv")
|
||||
if err != nil {
|
||||
t.Fatalf("open %s: %v", name, err)
|
||||
}
|
||||
defer f.Close()
|
||||
var rows [][]string
|
||||
sc := bufio.NewScanner(f)
|
||||
first := true
|
||||
for sc.Scan() {
|
||||
line := sc.Text()
|
||||
if first {
|
||||
first = false
|
||||
continue
|
||||
}
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
rows = append(rows, strings.Split(line, ","))
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
func goldenCell(s string) float64 {
|
||||
if s == "nan" {
|
||||
return math.NaN()
|
||||
}
|
||||
v, _ := strconv.ParseFloat(s, 64)
|
||||
return v
|
||||
}
|
||||
|
||||
func goldenInput(t *testing.T) [][]float64 {
|
||||
rows := readGolden(t, "input")
|
||||
out := make([][]float64, len(rows))
|
||||
for i, r := range rows {
|
||||
vals := make([]float64, len(r))
|
||||
for j, c := range r {
|
||||
vals[j] = goldenCell(c)
|
||||
}
|
||||
out[i] = vals
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func assertGoldenClose(t *testing.T, got, want float64, row int, field string) {
|
||||
t.Helper()
|
||||
if math.IsNaN(want) {
|
||||
if !math.IsNaN(got) {
|
||||
t.Errorf("row %d %s: expected warmup/NaN, got %v", row, field, got)
|
||||
}
|
||||
return
|
||||
}
|
||||
tol := goldenTol * math.Max(1.0, math.Abs(want))
|
||||
if math.Abs(got-want) > tol {
|
||||
t.Errorf("row %d %s: got %v want %v", row, field, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoldenScalar(t *testing.T) {
|
||||
input := goldenInput(t)
|
||||
sma, err := NewSma(14)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer sma.Close()
|
||||
ema, err := NewEma(14)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ema.Close()
|
||||
rsi, err := NewRsi(14)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer rsi.Close()
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
upd func(close float64) float64
|
||||
}{
|
||||
{"sma", sma.Update},
|
||||
{"ema", ema.Update},
|
||||
{"rsi", rsi.Update},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
exp := readGolden(t, tc.name)
|
||||
for i := range input {
|
||||
assertGoldenClose(t, tc.upd(input[i][3]), goldenCell(exp[i][0]), i, tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoldenAtr(t *testing.T) {
|
||||
input := goldenInput(t)
|
||||
exp := readGolden(t, "atr")
|
||||
atr, err := NewAtr(14)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer atr.Close()
|
||||
for i := range input {
|
||||
got := atr.Update(input[i][0], input[i][1], input[i][2], input[i][3], input[i][4], int64(i))
|
||||
assertGoldenClose(t, got, goldenCell(exp[i][0]), i, "atr")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoldenBeta(t *testing.T) {
|
||||
input := goldenInput(t)
|
||||
exp := readGolden(t, "beta")
|
||||
beta, err := NewBeta(20)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer beta.Close()
|
||||
for i := range input {
|
||||
// generator fed (close, open)
|
||||
assertGoldenClose(t, beta.Update(input[i][3], input[i][0]), goldenCell(exp[i][0]), i, "beta")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoldenMacd(t *testing.T) {
|
||||
input := goldenInput(t)
|
||||
exp := readGolden(t, "macd")
|
||||
macd, err := NewMacdIndicator(12, 26, 9)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer macd.Close()
|
||||
for i := range input {
|
||||
out, ok := macd.Update(input[i][3])
|
||||
if exp[i][0] == "nan" {
|
||||
if ok {
|
||||
t.Errorf("row %d macd: expected warmup, got %+v", i, out)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !ok {
|
||||
t.Errorf("row %d macd: expected value, got warmup", i)
|
||||
continue
|
||||
}
|
||||
assertGoldenClose(t, out.Macd, goldenCell(exp[i][0]), i, "macd.macd")
|
||||
assertGoldenClose(t, out.Signal, goldenCell(exp[i][1]), i, "macd.signal")
|
||||
assertGoldenClose(t, out.Histogram, goldenCell(exp[i][2]), i, "macd.histogram")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoldenAdx(t *testing.T) {
|
||||
input := goldenInput(t)
|
||||
exp := readGolden(t, "adx")
|
||||
adx, err := NewAdx(14)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer adx.Close()
|
||||
for i := range input {
|
||||
out, ok := adx.Update(input[i][0], input[i][1], input[i][2], input[i][3], input[i][4], int64(i))
|
||||
if exp[i][0] == "nan" {
|
||||
if ok {
|
||||
t.Errorf("row %d adx: expected warmup, got %+v", i, out)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !ok {
|
||||
t.Errorf("row %d adx: expected value, got warmup", i)
|
||||
continue
|
||||
}
|
||||
assertGoldenClose(t, out.PlusDi, goldenCell(exp[i][0]), i, "adx.plus_di")
|
||||
assertGoldenClose(t, out.MinusDi, goldenCell(exp[i][1]), i, "adx.minus_di")
|
||||
assertGoldenClose(t, out.Adx, goldenCell(exp[i][2]), i, "adx.adx")
|
||||
}
|
||||
}
|
||||
@@ -30,14 +30,14 @@ Maven:
|
||||
<dependency>
|
||||
<groupId>org.wickra</groupId>
|
||||
<artifactId>wickra</artifactId>
|
||||
<version>0.8.4</version>
|
||||
<version>0.8.8</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
Gradle:
|
||||
|
||||
```kotlin
|
||||
implementation("org.wickra:wickra:0.8.4")
|
||||
implementation("org.wickra:wickra:0.8.8")
|
||||
```
|
||||
|
||||
The native library ships prebuilt per platform (Linux, macOS, Windows — x64 and
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>org.wickra</groupId>
|
||||
<artifactId>wickra</artifactId>
|
||||
<version>0.8.4</version>
|
||||
<version>0.8.8</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Wickra</name>
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
package org.wickra;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Golden-fixture parity: replay the shared {@code testdata/golden} input series
|
||||
* through the Java FFI and assert every value matches the Rust reference output.
|
||||
* Where the archetype tests only check finiteness, this pins exact values, so a
|
||||
* wiring bug (swapped parameter, wrong multi-output field) is caught. Fixtures
|
||||
* are generated by {@code cargo run -p wickra-examples --bin gen_golden}.
|
||||
*/
|
||||
class GoldenTests {
|
||||
private static final double TOL = 1e-6;
|
||||
|
||||
private static Path goldenDir() {
|
||||
File d = new File("").getAbsoluteFile();
|
||||
while (d != null) {
|
||||
File g = new File(d, "testdata/golden");
|
||||
if (g.isDirectory()) {
|
||||
return g.toPath();
|
||||
}
|
||||
d = d.getParentFile();
|
||||
}
|
||||
throw new IllegalStateException("testdata/golden not found from " + new File("").getAbsolutePath());
|
||||
}
|
||||
|
||||
private static List<String[]> readCsv(String name) throws Exception {
|
||||
List<String> lines = Files.readAllLines(goldenDir().resolve(name + ".csv"));
|
||||
List<String[]> rows = new ArrayList<>();
|
||||
for (int i = 1; i < lines.size(); i++) { // skip header
|
||||
if (!lines.get(i).isEmpty()) {
|
||||
rows.add(lines.get(i).split(","));
|
||||
}
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
private static double cell(String s) {
|
||||
return s.equals("nan") ? Double.NaN : Double.parseDouble(s);
|
||||
}
|
||||
|
||||
private static double[][] input() throws Exception {
|
||||
List<String[]> rows = readCsv("input");
|
||||
double[][] out = new double[rows.size()][];
|
||||
for (int i = 0; i < rows.size(); i++) {
|
||||
String[] r = rows.get(i);
|
||||
double[] v = new double[r.length];
|
||||
for (int j = 0; j < r.length; j++) {
|
||||
v[j] = Double.parseDouble(r[j]);
|
||||
}
|
||||
out[i] = v;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private static void close(double got, double want, int row, String field) {
|
||||
if (Double.isNaN(want)) {
|
||||
assertTrue(Double.isNaN(got), "row " + row + " " + field + ": expected warmup/NaN, got " + got);
|
||||
return;
|
||||
}
|
||||
double tol = TOL * Math.max(1.0, Math.abs(want));
|
||||
assertTrue(Math.abs(got - want) <= tol, "row " + row + " " + field + ": got " + got + " want " + want);
|
||||
}
|
||||
|
||||
@Test
|
||||
void scalarMatchesGolden() throws Exception {
|
||||
double[][] in = input();
|
||||
try (Sma sma = new Sma(14)) {
|
||||
List<String[]> e = readCsv("sma");
|
||||
for (int i = 0; i < in.length; i++) {
|
||||
close(sma.update(in[i][3]), cell(e.get(i)[0]), i, "sma");
|
||||
}
|
||||
}
|
||||
try (Ema ema = new Ema(14)) {
|
||||
List<String[]> e = readCsv("ema");
|
||||
for (int i = 0; i < in.length; i++) {
|
||||
close(ema.update(in[i][3]), cell(e.get(i)[0]), i, "ema");
|
||||
}
|
||||
}
|
||||
try (Rsi rsi = new Rsi(14)) {
|
||||
List<String[]> e = readCsv("rsi");
|
||||
for (int i = 0; i < in.length; i++) {
|
||||
close(rsi.update(in[i][3]), cell(e.get(i)[0]), i, "rsi");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void candleAtrMatchesGolden() throws Exception {
|
||||
double[][] in = input();
|
||||
List<String[]> e = readCsv("atr");
|
||||
try (Atr atr = new Atr(14)) {
|
||||
for (int i = 0; i < in.length; i++) {
|
||||
close(atr.update(in[i][0], in[i][1], in[i][2], in[i][3], in[i][4], i), cell(e.get(i)[0]), i, "atr");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void pairwiseBetaMatchesGolden() throws Exception {
|
||||
double[][] in = input();
|
||||
List<String[]> e = readCsv("beta");
|
||||
try (Beta beta = new Beta(20)) {
|
||||
for (int i = 0; i < in.length; i++) {
|
||||
// generator fed (close, open)
|
||||
close(beta.update(in[i][3], in[i][0]), cell(e.get(i)[0]), i, "beta");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void macdMatchesGolden() throws Exception {
|
||||
double[][] in = input();
|
||||
List<String[]> e = readCsv("macd");
|
||||
try (MacdIndicator macd = new MacdIndicator(12, 26, 9)) {
|
||||
for (int i = 0; i < in.length; i++) {
|
||||
MacdOutput o = macd.update(in[i][3]);
|
||||
String[] row = e.get(i);
|
||||
if (row[0].equals("nan")) {
|
||||
assertNull(o, "row " + i + " macd: expected warmup");
|
||||
continue;
|
||||
}
|
||||
assertNotNull(o, "row " + i + " macd: expected value");
|
||||
close(o.macd(), cell(row[0]), i, "macd.macd");
|
||||
close(o.signal(), cell(row[1]), i, "macd.signal");
|
||||
close(o.histogram(), cell(row[2]), i, "macd.histogram");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void adxMatchesGolden() throws Exception {
|
||||
double[][] in = input();
|
||||
List<String[]> e = readCsv("adx");
|
||||
try (Adx adx = new Adx(14)) {
|
||||
for (int i = 0; i < in.length; i++) {
|
||||
AdxOutput o = adx.update(in[i][0], in[i][1], in[i][2], in[i][3], in[i][4], i);
|
||||
String[] row = e.get(i);
|
||||
if (row[0].equals("nan")) {
|
||||
assertNull(o, "row " + i + " adx: expected warmup");
|
||||
continue;
|
||||
}
|
||||
assertNotNull(o, "row " + i + " adx: expected value");
|
||||
close(o.plusDi(), cell(row[0]), i, "adx.plus_di");
|
||||
close(o.minusDi(), cell(row[1]), i, "adx.minus_di");
|
||||
close(o.adx(), cell(row[2]), i, "adx.adx");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-darwin-arm64",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.8",
|
||||
"description": "Native binding for wickra (macOS Apple Silicon). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.darwin-arm64.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-darwin-x64",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.8",
|
||||
"description": "Native binding for wickra (macOS Intel). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.darwin-x64.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-linux-arm64-gnu",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.8",
|
||||
"description": "Native binding for wickra (linux arm64 GNU). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.linux-arm64-gnu.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-linux-x64-gnu",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.8",
|
||||
"description": "Native binding for wickra (linux x64 GNU). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.linux-x64-gnu.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-win32-arm64-msvc",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.8",
|
||||
"description": "Native binding for wickra (Windows arm64 MSVC). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.win32-arm64-msvc.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-win32-x64-msvc",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.8",
|
||||
"description": "Native binding for wickra (Windows x64 MSVC). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.win32-x64-msvc.node",
|
||||
"files": [
|
||||
|
||||
Generated
+20
-20
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "wickra",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.8",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wickra",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.8",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@napi-rs/cli": "^2.18.0"
|
||||
@@ -15,12 +15,12 @@
|
||||
"node": ">= 18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"wickra-darwin-arm64": "0.8.4",
|
||||
"wickra-darwin-x64": "0.8.4",
|
||||
"wickra-linux-arm64-gnu": "0.8.4",
|
||||
"wickra-linux-x64-gnu": "0.8.4",
|
||||
"wickra-win32-arm64-msvc": "0.8.4",
|
||||
"wickra-win32-x64-msvc": "0.8.4"
|
||||
"wickra-darwin-arm64": "0.8.8",
|
||||
"wickra-darwin-x64": "0.8.8",
|
||||
"wickra-linux-arm64-gnu": "0.8.8",
|
||||
"wickra-linux-x64-gnu": "0.8.8",
|
||||
"wickra-win32-arm64-msvc": "0.8.8",
|
||||
"wickra-win32-x64-msvc": "0.8.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/cli": {
|
||||
@@ -41,8 +41,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wickra-darwin-arm64": {
|
||||
"version": "0.8.4",
|
||||
"resolved": "https://registry.npmjs.org/wickra-darwin-arm64/-/wickra-darwin-arm64-0.8.4.tgz",
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/wickra-darwin-arm64/-/wickra-darwin-arm64-0.8.8.tgz",
|
||||
"integrity": "sha512-4eZiBR/yGUdr4nzhEUFy2i69XgNx64iI2ax/LPamsThgylC0KpHOZKK19QzJ2d9KbK4C8nMjME5FLuR+4GNEwQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
@@ -57,8 +57,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wickra-darwin-x64": {
|
||||
"version": "0.8.4",
|
||||
"resolved": "https://registry.npmjs.org/wickra-darwin-x64/-/wickra-darwin-x64-0.8.4.tgz",
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/wickra-darwin-x64/-/wickra-darwin-x64-0.8.8.tgz",
|
||||
"integrity": "sha512-6hf8zI3QPjTFp4zCpmgUwDvNtu6jHqNUHKD5e55POo0CgA52HkpyxSPtVm8TGTIZDI7kPjlbOdBM8CJ76mmXwA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
@@ -73,8 +73,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wickra-linux-arm64-gnu": {
|
||||
"version": "0.8.4",
|
||||
"resolved": "https://registry.npmjs.org/wickra-linux-arm64-gnu/-/wickra-linux-arm64-gnu-0.8.4.tgz",
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/wickra-linux-arm64-gnu/-/wickra-linux-arm64-gnu-0.8.8.tgz",
|
||||
"integrity": "sha512-kSe6y0xBMSiqdPLXNjwop5WZdHtvdBNKSEBCwZ4hFq33p4apW25/wrlzv9/oDuyD4kuPabJEhCCnFOplh58CUg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
@@ -89,8 +89,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wickra-linux-x64-gnu": {
|
||||
"version": "0.8.4",
|
||||
"resolved": "https://registry.npmjs.org/wickra-linux-x64-gnu/-/wickra-linux-x64-gnu-0.8.4.tgz",
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/wickra-linux-x64-gnu/-/wickra-linux-x64-gnu-0.8.8.tgz",
|
||||
"integrity": "sha512-tWBWS4qz7hxM4xnpFb59bhf6TaLwXq0Z3jEa/2l7r8PiHA94g8r8S53NRMiT+4yiL5hSWe/nUiC/YXdRrhEZ4g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
@@ -105,8 +105,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wickra-win32-arm64-msvc": {
|
||||
"version": "0.8.4",
|
||||
"resolved": "https://registry.npmjs.org/wickra-win32-arm64-msvc/-/wickra-win32-arm64-msvc-0.8.4.tgz",
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/wickra-win32-arm64-msvc/-/wickra-win32-arm64-msvc-0.8.8.tgz",
|
||||
"integrity": "sha512-EXIckHxAtF75PUGDKRzXyqMe9ldP0JjSdu68WFN6iJfp+McYrGu6h40TEJlQ/oUEIoPqiZB/xhVyo/el5Lg7zw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
@@ -121,8 +121,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wickra-win32-x64-msvc": {
|
||||
"version": "0.8.4",
|
||||
"resolved": "https://registry.npmjs.org/wickra-win32-x64-msvc/-/wickra-win32-x64-msvc-0.8.4.tgz",
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/wickra-win32-x64-msvc/-/wickra-win32-x64-msvc-0.8.8.tgz",
|
||||
"integrity": "sha512-Yfsqq1Xwp6hdxMyLze411vNdo7BDwI6+lPSe7A9XdqyPecNDbtKwYLpsal2r8EHbNzqM+R8XnuRtUaEQS5VlUQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.8",
|
||||
"description": "Streaming-first technical indicators: incremental, fast, install-free. Node bindings powered by Rust.",
|
||||
"author": "kingchenc <support@wickra.org>",
|
||||
"main": "index.js",
|
||||
@@ -47,12 +47,12 @@
|
||||
"node": ">= 18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"wickra-linux-x64-gnu": "0.8.4",
|
||||
"wickra-linux-arm64-gnu": "0.8.4",
|
||||
"wickra-darwin-x64": "0.8.4",
|
||||
"wickra-darwin-arm64": "0.8.4",
|
||||
"wickra-win32-x64-msvc": "0.8.4",
|
||||
"wickra-win32-arm64-msvc": "0.8.4"
|
||||
"wickra-linux-x64-gnu": "0.8.8",
|
||||
"wickra-linux-arm64-gnu": "0.8.8",
|
||||
"wickra-darwin-x64": "0.8.8",
|
||||
"wickra-darwin-arm64": "0.8.8",
|
||||
"wickra-win32-x64-msvc": "0.8.8",
|
||||
"wickra-win32-arm64-msvc": "0.8.8"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "napi build --platform --release",
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "wickra"
|
||||
version = "0.8.4"
|
||||
version = "0.8.8"
|
||||
description = "Streaming-first technical indicators: incremental, fast, install-free."
|
||||
readme = "README.md"
|
||||
license = "MIT OR Apache-2.0"
|
||||
@@ -48,6 +48,7 @@ bench = [
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/wickra-lib/wickra"
|
||||
Documentation = "https://docs.wickra.org"
|
||||
Repository = "https://github.com/wickra-lib/wickra"
|
||||
Issues = "https://github.com/wickra-lib/wickra/issues"
|
||||
|
||||
|
||||
@@ -11,3 +11,4 @@
|
||||
^src/wickra-c$
|
||||
^src/Makevars$
|
||||
^\.gitignore$
|
||||
^data-raw$
|
||||
|
||||
+10
-3
@@ -1,15 +1,19 @@
|
||||
Package: wickra
|
||||
Type: Package
|
||||
Title: Streaming-First Technical Indicators
|
||||
Version: 0.8.4
|
||||
Version: 0.8.8
|
||||
Authors@R: person("Wickra contributors", role = c("aut", "cre"), email = "support@wickra.org")
|
||||
Description: R bindings for the Wickra technical-analysis library over its C ABI
|
||||
hub. Exposes 514 indicators, each an O(1) streaming state machine shared with
|
||||
the Rust core and the other language bindings, so that live and historical
|
||||
evaluation use the exact same implementation.
|
||||
License: MIT + file LICENSE | Apache License 2.0
|
||||
URL: https://github.com/wickra-lib/wickra, https://docs.wickra.org
|
||||
URL: https://github.com/wickra-lib/wickra, https://docs.wickra.org,
|
||||
https://wickra-lib.r-universe.dev
|
||||
BugReports: https://github.com/wickra-lib/wickra/issues
|
||||
X-schema.org-keywords: technical-analysis, indicators, streaming, trading,
|
||||
finance, quant, algorithmic-trading, backtesting, time-series, ta-lib,
|
||||
candlestick, market-data
|
||||
Encoding: UTF-8
|
||||
NeedsCompilation: yes
|
||||
SystemRequirements: the Wickra C ABI shared library, downloaded automatically at
|
||||
@@ -17,6 +21,9 @@ SystemRequirements: the Wickra C ABI shared library, downloaded automatically at
|
||||
Set WICKRA_INCLUDE_DIR and WICKRA_LIB_DIR to build against a locally built C
|
||||
ABI instead (e.g. after `cargo build -p wickra-c --release`).
|
||||
Roxygen: list(markdown = TRUE)
|
||||
Suggests: testthat (>= 3.0.0)
|
||||
Depends: R (>= 2.10)
|
||||
Suggests: testthat (>= 3.0.0), knitr, rmarkdown
|
||||
VignetteBuilder: knitr
|
||||
LazyData: true
|
||||
Config/testthat/edition: 3
|
||||
Config/roxygen2/version: 8.0.0
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#' Synthetic daily OHLCV sample series
|
||||
#'
|
||||
#' A deterministic, synthetic daily OHLCV (open / high / low / close / volume)
|
||||
#' price series for use in the examples, the *Getting started* vignette, and
|
||||
#' tests. It is a seeded random walk, **not** real market data. Regenerate with
|
||||
#' `data-raw/sample_ohlcv.R`.
|
||||
#'
|
||||
#' @format A data frame with 250 rows and 6 columns:
|
||||
#' \describe{
|
||||
#' \item{date}{Trading date (`Date`).}
|
||||
#' \item{open}{Opening price.}
|
||||
#' \item{high}{Session high.}
|
||||
#' \item{low}{Session low.}
|
||||
#' \item{close}{Closing price.}
|
||||
#' \item{volume}{Traded volume.}
|
||||
#' }
|
||||
"sample_ohlcv"
|
||||
@@ -1,4 +1,4 @@
|
||||
# Wickra — R
|
||||
# Wickra — R <img src="man/figures/logo.png" align="right" height="120" alt="Wickra logo" />
|
||||
|
||||
[](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/wickra-lib/wickra)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Generates data/sample_ohlcv.rda — a deterministic, synthetic daily OHLCV
|
||||
# series used by the examples, the getting-started vignette, and tests. It is a
|
||||
# seeded random walk, NOT real market data.
|
||||
#
|
||||
# Regenerate (run from the R package root, bindings/r):
|
||||
# Rscript data-raw/sample_ohlcv.R
|
||||
|
||||
set.seed(42)
|
||||
n <- 250L
|
||||
dates <- seq(as.Date("2023-01-02"), by = "day", length.out = n)
|
||||
|
||||
# Random-walk close with a mild upward drift; derive OHLC around it.
|
||||
returns <- rnorm(n, mean = 0.0004, sd = 0.012)
|
||||
close <- round(100 * cumprod(1 + returns), 2)
|
||||
open <- round(c(100, head(close, -1)) * (1 + rnorm(n, 0, 0.003)), 2)
|
||||
high <- round(pmax(open, close) * (1 + abs(rnorm(n, 0, 0.004))), 2)
|
||||
low <- round(pmin(open, close) * (1 - abs(rnorm(n, 0, 0.004))), 2)
|
||||
volume <- round(1e6 * exp(rnorm(n, 0, 0.3)))
|
||||
|
||||
sample_ohlcv <- data.frame(
|
||||
date = dates,
|
||||
open = open,
|
||||
high = high,
|
||||
low = low,
|
||||
close = close,
|
||||
volume = volume
|
||||
)
|
||||
|
||||
save(sample_ohlcv, file = "data/sample_ohlcv.rda", compress = "xz", version = 2)
|
||||
cat(sprintf("wrote data/sample_ohlcv.rda: %d rows x %d cols\n",
|
||||
nrow(sample_ohlcv), ncol(sample_ohlcv)))
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -0,0 +1,27 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/data.R
|
||||
\docType{data}
|
||||
\name{sample_ohlcv}
|
||||
\alias{sample_ohlcv}
|
||||
\title{Synthetic daily OHLCV sample series}
|
||||
\format{
|
||||
A data frame with 250 rows and 6 columns:
|
||||
\describe{
|
||||
\item{date}{Trading date (\code{Date}).}
|
||||
\item{open}{Opening price.}
|
||||
\item{high}{Session high.}
|
||||
\item{low}{Session low.}
|
||||
\item{close}{Closing price.}
|
||||
\item{volume}{Traded volume.}
|
||||
}
|
||||
}
|
||||
\usage{
|
||||
sample_ohlcv
|
||||
}
|
||||
\description{
|
||||
A deterministic, synthetic daily OHLCV (open / high / low / close / volume)
|
||||
price series for use in the examples, the \emph{Getting started} vignette, and
|
||||
tests. It is a seeded random walk, \strong{not} real market data. Regenerate with
|
||||
\code{data-raw/sample_ohlcv.R}.
|
||||
}
|
||||
\keyword{datasets}
|
||||
@@ -0,0 +1,119 @@
|
||||
# Golden-fixture parity: replay the shared testdata/golden input series through
|
||||
# the R FFI and assert every value matches the Rust reference output. Where the
|
||||
# archetype test only checks finiteness, this pins exact values, catching wiring
|
||||
# bugs (swapped params, wrong multi-output field). Fixtures are generated by
|
||||
# `cargo run -p wickra-examples --bin gen_golden`.
|
||||
#
|
||||
# The fixtures live at the repository root (testdata/golden) and are present
|
||||
# during the monorepo test run, but they are NOT bundled into the standalone R
|
||||
# package. A packaged check (r-universe / CRAN) therefore cannot find them, so
|
||||
# these tests skip there; the parity is already enforced by the repository CI.
|
||||
|
||||
find_golden_dir <- function() {
|
||||
d <- normalizePath(getwd(), winslash = "/", mustWork = FALSE)
|
||||
repeat {
|
||||
g <- file.path(d, "testdata", "golden")
|
||||
if (dir.exists(g)) return(g)
|
||||
parent <- dirname(d)
|
||||
if (identical(parent, d)) return(NULL)
|
||||
d <- parent
|
||||
}
|
||||
}
|
||||
|
||||
golden_dir <- find_golden_dir()
|
||||
|
||||
skip_if_no_golden <- function() {
|
||||
skip_if(is.null(golden_dir), "golden fixtures not bundled with the package")
|
||||
}
|
||||
|
||||
read_golden <- function(name) {
|
||||
read.csv(file.path(golden_dir, paste0(name, ".csv")),
|
||||
colClasses = "character", check.names = FALSE)
|
||||
}
|
||||
|
||||
read_golden_input <- function() read.csv(file.path(golden_dir, "input.csv"))
|
||||
|
||||
gcell <- function(s) if (identical(s, "nan")) NA_real_ else as.numeric(s)
|
||||
|
||||
expect_close <- function(got, want, row, field) {
|
||||
if (is.na(want)) {
|
||||
expect_true(is.na(got), info = paste("row", row, field, "expected warmup/NA"))
|
||||
} else {
|
||||
tol <- 1e-6 * max(1, abs(want))
|
||||
expect_lte(abs(got - want), tol, label = paste("row", row, field, "got", got, "want", want))
|
||||
}
|
||||
}
|
||||
|
||||
test_that("scalar indicators match golden", {
|
||||
skip_if_no_golden()
|
||||
golden_input <- read_golden_input()
|
||||
specs <- list(c("sma", 14), c("ema", 14), c("rsi", 14))
|
||||
for (spec in specs) {
|
||||
name <- spec[[1]]
|
||||
ind <- switch(name, sma = Sma(14), ema = Ema(14), rsi = Rsi(14))
|
||||
exp <- read_golden(name)
|
||||
for (i in seq_len(nrow(golden_input))) {
|
||||
got <- update(ind, golden_input$close[i])
|
||||
expect_close(got, gcell(exp[i, 1]), i, name)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test_that("candle Atr matches golden", {
|
||||
skip_if_no_golden()
|
||||
golden_input <- read_golden_input()
|
||||
atr <- Atr(14)
|
||||
exp <- read_golden("atr")
|
||||
for (i in seq_len(nrow(golden_input))) {
|
||||
got <- update(atr, golden_input$open[i], golden_input$high[i], golden_input$low[i],
|
||||
golden_input$close[i], golden_input$volume[i], i - 1)
|
||||
expect_close(got, gcell(exp[i, 1]), i, "atr")
|
||||
}
|
||||
})
|
||||
|
||||
test_that("pairwise Beta matches golden", {
|
||||
skip_if_no_golden()
|
||||
golden_input <- read_golden_input()
|
||||
beta <- Beta(20)
|
||||
exp <- read_golden("beta")
|
||||
for (i in seq_len(nrow(golden_input))) {
|
||||
# generator fed (close, open)
|
||||
got <- update(beta, golden_input$close[i], golden_input$open[i])
|
||||
expect_close(got, gcell(exp[i, 1]), i, "beta")
|
||||
}
|
||||
})
|
||||
|
||||
test_that("multi-output MACD matches golden", {
|
||||
skip_if_no_golden()
|
||||
golden_input <- read_golden_input()
|
||||
macd <- MacdIndicator(12, 26, 9)
|
||||
exp <- read_golden("macd")
|
||||
for (i in seq_len(nrow(golden_input))) {
|
||||
out <- update(macd, golden_input$close[i])
|
||||
if (identical(exp[i, "macd"], "nan")) {
|
||||
expect_true(all(is.na(out)), info = paste("row", i, "macd warmup"))
|
||||
} else {
|
||||
expect_close(out[["macd"]], gcell(exp[i, "macd"]), i, "macd.macd")
|
||||
expect_close(out[["signal"]], gcell(exp[i, "signal"]), i, "macd.signal")
|
||||
expect_close(out[["histogram"]], gcell(exp[i, "histogram"]), i, "macd.histogram")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test_that("multi-output ADX matches golden", {
|
||||
skip_if_no_golden()
|
||||
golden_input <- read_golden_input()
|
||||
adx <- Adx(14)
|
||||
exp <- read_golden("adx")
|
||||
for (i in seq_len(nrow(golden_input))) {
|
||||
out <- update(adx, golden_input$open[i], golden_input$high[i], golden_input$low[i],
|
||||
golden_input$close[i], golden_input$volume[i], i - 1)
|
||||
if (identical(exp[i, "plus_di"], "nan")) {
|
||||
expect_true(all(is.na(out)), info = paste("row", i, "adx warmup"))
|
||||
} else {
|
||||
expect_close(out[["plus_di"]], gcell(exp[i, "plus_di"]), i, "adx.plus_di")
|
||||
expect_close(out[["minus_di"]], gcell(exp[i, "minus_di"]), i, "adx.minus_di")
|
||||
expect_close(out[["adx"]], gcell(exp[i, "adx"]), i, "adx.adx")
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
title: "Getting started with wickra"
|
||||
output: rmarkdown::html_vignette
|
||||
vignette: >
|
||||
%\VignetteIndexEntry{Getting started with wickra}
|
||||
%\VignetteEngine{knitr::rmarkdown}
|
||||
%\VignetteEncoding{UTF-8}
|
||||
---
|
||||
|
||||
```{r setup, include = FALSE}
|
||||
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
|
||||
```
|
||||
|
||||
`wickra` exposes the Wickra technical-analysis library in R over its C ABI hub.
|
||||
Every indicator is a constructor returning a `wickra_indicator`; you feed it data
|
||||
one observation at a time with `update()` (an O(1) streaming step) or run a whole
|
||||
series at once with `batch()`. Both paths share the exact same Rust core, so a
|
||||
live feed and a historical backtest compute identical values.
|
||||
|
||||
```{r}
|
||||
library(wickra)
|
||||
```
|
||||
|
||||
## A sample series
|
||||
|
||||
The package ships a small synthetic OHLCV series, `sample_ohlcv`, for examples
|
||||
(a seeded random walk — not real market data).
|
||||
|
||||
```{r}
|
||||
head(sample_ohlcv)
|
||||
```
|
||||
|
||||
## Batch: a whole series at once
|
||||
|
||||
Scalar indicators run over a vector with `batch()`. Warmup positions are `NA`.
|
||||
|
||||
```{r}
|
||||
sma <- Sma(20)
|
||||
sma_values <- batch(sma, sample_ohlcv$close)
|
||||
tail(sma_values)
|
||||
```
|
||||
|
||||
## Streaming: one observation at a time
|
||||
|
||||
The same indicator fed tick-by-tick with `update()` returns the identical
|
||||
values — an equivalence the test suite enforces for every indicator.
|
||||
|
||||
```{r}
|
||||
sma_stream <- Sma(20)
|
||||
streamed <- vapply(sample_ohlcv$close, function(p) update(sma_stream, p), numeric(1))
|
||||
|
||||
same_warmup <- all(is.na(streamed) == is.na(sma_values))
|
||||
same_values <- all(streamed == sma_values, na.rm = TRUE)
|
||||
c(batch_equals_streaming = same_warmup && same_values)
|
||||
```
|
||||
|
||||
A typical streaming loop reacts to each value as it arrives:
|
||||
|
||||
```{r}
|
||||
rsi <- Rsi(14)
|
||||
overbought_days <- 0L
|
||||
for (price in sample_ohlcv$close) {
|
||||
v <- update(rsi, price) # NA during warmup
|
||||
if (!is.na(v) && v > 70) overbought_days <- overbought_days + 1L
|
||||
}
|
||||
overbought_days
|
||||
```
|
||||
|
||||
## Multi-output indicators
|
||||
|
||||
Indicators with several outputs return a *named* numeric vector (`NA` while
|
||||
warming up). MACD is the classic example — line, signal, and histogram:
|
||||
|
||||
```{r}
|
||||
macd <- MacdIndicator(12, 26, 9)
|
||||
last_macd <- c(macd = NA, signal = NA, histogram = NA)
|
||||
for (price in sample_ohlcv$close) last_macd <- update(macd, price)
|
||||
last_macd
|
||||
```
|
||||
|
||||
## Candle indicators
|
||||
|
||||
Indicators that need the whole bar take the OHLCV fields plus a timestamp:
|
||||
|
||||
```{r}
|
||||
atr <- Atr(14)
|
||||
last_atr <- NA_real_
|
||||
for (i in seq_len(nrow(sample_ohlcv))) {
|
||||
last_atr <- update(
|
||||
atr,
|
||||
sample_ohlcv$open[i], sample_ohlcv$high[i], sample_ohlcv$low[i],
|
||||
sample_ohlcv$close[i], sample_ohlcv$volume[i], i - 1
|
||||
)
|
||||
}
|
||||
last_atr
|
||||
```
|
||||
|
||||
## Resetting state
|
||||
|
||||
`reset()` returns an indicator to its warmup state so the same object can be
|
||||
reused on a fresh series:
|
||||
|
||||
```{r}
|
||||
reset(sma)
|
||||
update(sma, 100) # NaN — warming up again
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- Full indicator catalogue, guides, and per-indicator reference:
|
||||
<https://docs.wickra.org>.
|
||||
- Every constructor (`Sma()`, `Rsi()`, `MacdIndicator()`, `Atr()`, …) is listed
|
||||
in this package's help index.
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>org.wickra.examples</groupId>
|
||||
<artifactId>wickra-examples</artifactId>
|
||||
<version>0.8.4</version>
|
||||
<version>0.8.8</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Wickra Java examples</name>
|
||||
@@ -21,7 +21,7 @@
|
||||
<dependency>
|
||||
<groupId>org.wickra</groupId>
|
||||
<artifactId>wickra</artifactId>
|
||||
<version>0.8.4</version>
|
||||
<version>0.8.8</version>
|
||||
</dependency>
|
||||
<!-- Only the network examples (fetch_btcusdt) parse JSON. -->
|
||||
<dependency>
|
||||
|
||||
Generated
+7
-7
@@ -17,7 +17,7 @@
|
||||
},
|
||||
"../../bindings/node": {
|
||||
"name": "wickra",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.8",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@napi-rs/cli": "^2.18.0"
|
||||
@@ -26,12 +26,12 @@
|
||||
"node": ">= 18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"wickra-darwin-arm64": "0.8.4",
|
||||
"wickra-darwin-x64": "0.8.4",
|
||||
"wickra-linux-arm64-gnu": "0.8.4",
|
||||
"wickra-linux-x64-gnu": "0.8.4",
|
||||
"wickra-win32-arm64-msvc": "0.8.4",
|
||||
"wickra-win32-x64-msvc": "0.8.4"
|
||||
"wickra-darwin-arm64": "0.8.8",
|
||||
"wickra-darwin-x64": "0.8.8",
|
||||
"wickra-linux-arm64-gnu": "0.8.8",
|
||||
"wickra-linux-x64-gnu": "0.8.8",
|
||||
"wickra-win32-arm64-msvc": "0.8.8",
|
||||
"wickra-win32-x64-msvc": "0.8.8"
|
||||
}
|
||||
},
|
||||
"node_modules/wickra": {
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
//! Generate the language-neutral golden fixtures consumed by the per-binding
|
||||
//! parity runners (`bindings/{csharp,go,java,r}`).
|
||||
//!
|
||||
//! Run from the repo root: `cargo run -p wickra-examples --bin gen_golden`.
|
||||
//! It writes a deterministic OHLCV input series plus the reference outputs of a
|
||||
//! curated set of indicators spanning the FFI archetypes (scalar, candle,
|
||||
//! scalar multi-output, candle multi-output, pairwise), computed by the Rust
|
||||
//! core. Each binding runner replays the same input through its own FFI and
|
||||
//! checks it matches these values — catching wiring bugs (swapped params,
|
||||
//! wrong multi-output index) that the math-only core tests cannot see.
|
||||
//!
|
||||
//! `nan` marks a warmup slot where the indicator returned `None`.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use wickra::{Adx, Atr, Beta, Candle, Ema, Indicator, MacdIndicator, Rsi, Sma};
|
||||
|
||||
const N: usize = 80;
|
||||
|
||||
/// Deterministic OHLCV bar `i`: a varied, non-degenerate path so every
|
||||
/// indicator gets real movement (no constant returns, no zero ranges).
|
||||
fn bar(i: usize) -> (f64, f64, f64, f64, f64) {
|
||||
let t = i as f64;
|
||||
let close = 100.0 + 10.0 * (t * 0.3).sin() + 0.5 * t;
|
||||
let open = close - (t * 0.5).cos();
|
||||
let span = 1.0 + 0.5 * (t * 0.7).sin().abs();
|
||||
let high = close.max(open) + span;
|
||||
let low = close.min(open) - span;
|
||||
let volume = 1000.0 + 100.0 * (t * 0.2).sin().abs();
|
||||
(open, high, low, close, volume)
|
||||
}
|
||||
|
||||
fn cell(v: Option<f64>) -> String {
|
||||
match v {
|
||||
Some(x) => format!("{x}"),
|
||||
None => "nan".to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_csv(dir: &Path, name: &str, header: &str, rows: &[String]) {
|
||||
let mut out = String::new();
|
||||
let _ = writeln!(out, "{header}");
|
||||
for r in rows {
|
||||
let _ = writeln!(out, "{r}");
|
||||
}
|
||||
let path = dir.join(format!("{name}.csv"));
|
||||
fs::write(&path, out).expect("write fixture");
|
||||
println!("wrote {}", path.display());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let dir = Path::new("testdata/golden");
|
||||
fs::create_dir_all(dir).expect("create testdata/golden");
|
||||
|
||||
let candles: Vec<Candle> = (0..N)
|
||||
.map(|i| {
|
||||
let (o, h, l, c, v) = bar(i);
|
||||
Candle::new(o, h, l, c, v, i as i64).expect("valid candle")
|
||||
})
|
||||
.collect();
|
||||
let closes: Vec<f64> = candles.iter().map(|c| c.close).collect();
|
||||
|
||||
// input.csv — the single shared series every runner reads.
|
||||
let mut input = vec![String::from("open,high,low,close,volume")];
|
||||
for c in &candles {
|
||||
input.push(format!(
|
||||
"{},{},{},{},{}",
|
||||
c.open, c.high, c.low, c.close, c.volume
|
||||
));
|
||||
}
|
||||
let input_header = input.remove(0);
|
||||
write_csv(dir, "input", &input_header, &input);
|
||||
|
||||
// scalar (close-driven), single output. Each is a distinct type, so write
|
||||
// them out separately rather than from a heterogeneous collection.
|
||||
{
|
||||
let mut sma = Sma::new(14).unwrap();
|
||||
let rows: Vec<String> = closes.iter().map(|&c| cell(sma.update(c))).collect();
|
||||
write_csv(dir, "sma", "sma", &rows);
|
||||
}
|
||||
{
|
||||
let mut ema = Ema::new(14).unwrap();
|
||||
let rows: Vec<String> = closes.iter().map(|&c| cell(ema.update(c))).collect();
|
||||
write_csv(dir, "ema", "ema", &rows);
|
||||
}
|
||||
{
|
||||
let mut rsi = Rsi::new(14).unwrap();
|
||||
let rows: Vec<String> = closes.iter().map(|&c| cell(rsi.update(c))).collect();
|
||||
write_csv(dir, "rsi", "rsi", &rows);
|
||||
}
|
||||
|
||||
// candle, single output.
|
||||
{
|
||||
let mut atr = Atr::new(14).unwrap();
|
||||
let rows: Vec<String> = candles.iter().map(|&c| cell(atr.update(c))).collect();
|
||||
write_csv(dir, "atr", "atr", &rows);
|
||||
}
|
||||
|
||||
// scalar multi-output: MACD(12,26,9).
|
||||
{
|
||||
let mut macd = MacdIndicator::new(12, 26, 9).unwrap();
|
||||
let rows: Vec<String> = closes
|
||||
.iter()
|
||||
.map(|&c| match macd.update(c) {
|
||||
Some(o) => format!("{},{},{}", o.macd, o.signal, o.histogram),
|
||||
None => "nan,nan,nan".to_owned(),
|
||||
})
|
||||
.collect();
|
||||
write_csv(dir, "macd", "macd,signal,histogram", &rows);
|
||||
}
|
||||
|
||||
// candle multi-output: ADX(14).
|
||||
{
|
||||
let mut adx = Adx::new(14).unwrap();
|
||||
let rows: Vec<String> = candles
|
||||
.iter()
|
||||
.map(|&c| match adx.update(c) {
|
||||
Some(o) => format!("{},{},{}", o.plus_di, o.minus_di, o.adx),
|
||||
None => "nan,nan,nan".to_owned(),
|
||||
})
|
||||
.collect();
|
||||
write_csv(dir, "adx", "plus_di,minus_di,adx", &rows);
|
||||
}
|
||||
|
||||
// pairwise: Beta(20) over (close, open).
|
||||
{
|
||||
let mut beta = Beta::new(20).unwrap();
|
||||
let rows: Vec<String> = candles
|
||||
.iter()
|
||||
.map(|&c| cell(beta.update((c.close, c.open))))
|
||||
.collect();
|
||||
write_csv(dir, "beta", "beta", &rows);
|
||||
}
|
||||
|
||||
println!("golden fixtures written to {}", dir.display());
|
||||
}
|
||||
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
plus_di,minus_di,adx
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
39.5757019682593,10.51553170206367,30.912276792040817
|
||||
37.536261624936586,10.906948307963743,32.63069750889788
|
||||
35.215165462446194,12.883060473369223,33.61637662813429
|
||||
32.86410166086221,15.606658308025656,33.758337048896145
|
||||
30.70333902684003,18.50628500756431,33.11744953242373
|
||||
28.583754140794692,21.990805693589266,31.683067176177246
|
||||
26.55934622279741,25.269437743189002,29.597761510222966
|
||||
24.849750313093512,27.34663879718962,27.82532441495794
|
||||
23.505186308008465,28.419972295720065,26.513882262566277
|
||||
22.24831894567969,28.255382095825222,25.469626589930424
|
||||
21.991214452481188,26.24217101526044,24.279889509686143
|
||||
23.0167314852192,24.206077112686202,22.725510472977113
|
||||
25.270075861089534,22.49633154108633,21.51703781909767
|
||||
28.167925277844184,20.797978949255484,21.055190823958306
|
||||
32.199512135355,19.002819811263755,21.39222118044018
|
||||
36.67556284467224,17.08189161927664,22.467654445091764
|
||||
39.66767810504092,15.312333278446436,24.027003737037383
|
||||
41.25710485757308,13.864063299710923,25.86050681733179
|
||||
41.90255145462447,12.778588478409224,27.8177163877859
|
||||
42.395628716412624,11.937994453509367,29.834786399099126
|
||||
41.39315313749411,11.291691494482587,31.784798356703554
|
||||
38.98369312390027,10.942263455121635,33.52631517717672
|
||||
36.80520205991526,11.790866997951634,34.808291852450445
|
||||
34.33471861125097,14.165199105275695,35.29246448522293
|
||||
31.575896425438806,17.056390539549085,34.90412360474046
|
||||
29.011655429985023,19.499990165743316,33.81146999165209
|
||||
26.941362744011517,21.41861333571675,32.21208520671275
|
||||
25.293388618220902,23.528371409730532,30.16945244226847
|
||||
23.70108159294569,26.085794270270323,28.356623123061247
|
||||
21.9818825371455,26.753559469925122,27.030505691607747
|
||||
20.4556018343849,25.575479039846915,25.894230469505597
|
||||
19.315305653157523,24.149775639951073,24.839117763267886
|
||||
20.15346427198841,22.836532180755725,23.510691119817217
|
||||
22.621623373749483,21.279561359099215,22.049713637827605
|
||||
26.102172398824052,19.564946484191104,21.497230627213543
|
||||
29.5794011460886,17.914862734831026,21.71599192763469
|
||||
33.103914522491884,16.421886804841026,22.570814571368153
|
||||
36.988461875248944,14.998303176938437,23.980008725527608
|
||||
39.75301194225335,13.75986552582622,25.73669586768207
|
||||
41.37315229671887,12.777991517838071,27.67023180773477
|
||||
42.48135161688847,11.981093863498268,29.693955639647385
|
||||
42.62294720176041,11.257736731480932,31.730983563876975
|
||||
40.47684671425082,10.451870979556956,33.67554918447296
|
||||
37.62379013468778,11.104415435913893,35.1575133843429
|
||||
35.445073236866044,12.840589537363048,35.99012453099969
|
||||
33.361147221464314,15.58241905716853,36.014040954862004
|
||||
30.784559395666363,20.10967847345435,34.9397977135121
|
||||
28.101022653590128,23.891333482064333,33.02243689823779
|
||||
25.724805235133402,26.22784634752717,30.732853434649453
|
||||
23.898483996930594,27.16675703876092,28.994806129209827
|
||||
22.507592062957475,27.59047661188655,27.648453495608493
|
||||
21.169522519356338,26.35196828602853,26.452526680749255
|
||||
21.224977830554703,24.775436644747092,25.11436900225873
|
||||
|
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
atr
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
3.917642936098542
|
||||
3.871756865753318
|
||||
3.8256550237571303
|
||||
3.775585219414474
|
||||
3.7359112048078584
|
||||
3.751806385408204
|
||||
3.844730678370346
|
||||
3.9663267478375337
|
||||
4.065925146592011
|
||||
4.103990051025662
|
||||
4.122277884333844
|
||||
4.120405500552875
|
||||
4.1099068422738645
|
||||
4.067219182386907
|
||||
3.965656623010464
|
||||
3.883731209815142
|
||||
3.8454426000158177
|
||||
3.827649810828608
|
||||
3.8056867488416217
|
||||
3.7971798302715882
|
||||
3.795930185925992
|
||||
3.768312827006575
|
||||
3.700099728786484
|
||||
3.6306300896424184
|
||||
3.63084862338228
|
||||
3.6560272497167245
|
||||
3.6536783654804816
|
||||
3.670527021756155
|
||||
3.731163563648225
|
||||
3.855191519830406
|
||||
3.994403105040647
|
||||
4.097289247845801
|
||||
4.128368657741341
|
||||
4.103844480606131
|
||||
4.0291518193306395
|
||||
3.972922779511551
|
||||
3.9077919971718877
|
||||
3.8900842871217334
|
||||
3.9281940607734454
|
||||
3.970355102352287
|
||||
3.970344885666312
|
||||
3.9271768651715058
|
||||
3.891868629198634
|
||||
3.896746818914544
|
||||
3.888594808948336
|
||||
3.8241554941261624
|
||||
3.755340593345057
|
||||
3.742402894117046
|
||||
3.779811441067645
|
||||
3.833276428397188
|
||||
3.8832337640008086
|
||||
3.9482678364884123
|
||||
3.9963590513965954
|
||||
3.9961613679725096
|
||||
3.957618048219805
|
||||
3.9111378825809897
|
||||
3.9118754285284236
|
||||
3.9079875306228926
|
||||
3.8519602816708205
|
||||
3.8003043443211753
|
||||
3.824279210324508
|
||||
3.89030736805505
|
||||
3.946176568396809
|
||||
3.944383618517461
|
||||
3.889018639116889
|
||||
3.8395240928112067
|
||||
3.792174559624793
|
||||
|
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
beta
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
0.9195261318785413
|
||||
0.922546057952995
|
||||
0.9270670303012646
|
||||
0.9360823119678988
|
||||
0.9520494101604974
|
||||
0.9734365033467753
|
||||
0.995093627699459
|
||||
1.0111583960294632
|
||||
1.018359059410051
|
||||
1.0174553154888744
|
||||
1.0121204526718954
|
||||
1.0067713468887387
|
||||
1.0049777031298115
|
||||
1.0087588074727343
|
||||
1.0182494903866188
|
||||
1.031286972171161
|
||||
1.0431058848104742
|
||||
1.0473159800278413
|
||||
1.0395185963505182
|
||||
1.0218520432290943
|
||||
1.0027356441997792
|
||||
0.989852175809267
|
||||
0.9830850966851594
|
||||
0.9757086459066595
|
||||
0.9639743320260056
|
||||
0.9518863451049362
|
||||
0.945167696468917
|
||||
0.9459710447944064
|
||||
0.9530453598334451
|
||||
0.9634788824656162
|
||||
0.973948405670025
|
||||
0.9815754255825168
|
||||
0.9846435781849213
|
||||
0.9830670028068416
|
||||
0.9783981708129912
|
||||
0.9733920844663336
|
||||
0.9713725848572005
|
||||
0.9755741087472364
|
||||
0.988273819307749
|
||||
1.0091885908656193
|
||||
1.0332355593672604
|
||||
1.0510340548483572
|
||||
1.057262107302167
|
||||
1.058580145340488
|
||||
1.0645933328050556
|
||||
1.0735088672694193
|
||||
1.0743308164692502
|
||||
1.0612002349944065
|
||||
1.0392533178013483
|
||||
1.0174419588972756
|
||||
1.0016230577141623
|
||||
0.9934855658174216
|
||||
0.9919410932606791
|
||||
0.9943630990130676
|
||||
0.9973488461009995
|
||||
0.9974248103764315
|
||||
0.9919840212101835
|
||||
0.9802751136245323
|
||||
0.9638604974880948
|
||||
0.9461133999713321
|
||||
0.9309659374652403
|
||||
|
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
ema
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
107.082865308575
|
||||
105.90971557088022
|
||||
104.81838000454273
|
||||
103.91437652548925
|
||||
103.29137341232037
|
||||
103.02217097393634
|
||||
103.15163412061464
|
||||
103.6921955736008
|
||||
104.62232136443316
|
||||
105.88806700052659
|
||||
107.40757775297398
|
||||
109.07812453770966
|
||||
110.78504123504803
|
||||
112.4117601975411
|
||||
113.85004525232907
|
||||
115.00950442946956
|
||||
115.8255294789832
|
||||
116.26495019544112
|
||||
116.32889606739172
|
||||
116.05260755010886
|
||||
115.50221201839392
|
||||
114.76875083248335
|
||||
113.95998970819002
|
||||
113.19074277367604
|
||||
112.57257361958058
|
||||
112.2037924360836
|
||||
112.16064199938042
|
||||
112.49045917546245
|
||||
113.20742223024638
|
||||
114.29126332917505
|
||||
115.68906080413531
|
||||
117.3199507165269
|
||||
119.08233652305883
|
||||
120.86295254590979
|
||||
122.54697139145239
|
||||
124.02825224132444
|
||||
125.2188143840051
|
||||
126.05668958634725
|
||||
126.51145173900844
|
||||
126.58692971020658
|
||||
126.32086097368011
|
||||
125.78151686199148
|
||||
125.06160082390045
|
||||
124.26996466927172
|
||||
123.5218827065933
|
||||
122.92875250508669
|
||||
122.58814223802023
|
||||
122.57507361058863
|
||||
122.93531900967452
|
||||
123.68131159273575
|
||||
124.79103363078006
|
||||
126.20998238510259
|
||||
127.85603789338172
|
||||
129.62679782427364
|
||||
131.408724185901
|
||||
133.0872848279711
|
||||
134.5571838169111
|
||||
135.7317668260377
|
||||
136.550761377433
|
||||
136.98566051598186
|
||||
137.04226900211742
|
||||
136.7601845743594
|
||||
136.20926061449748
|
||||
135.48336619117217
|
||||
134.6920008752563
|
||||
133.95051334772793
|
||||
133.369797540168
|
||||
|
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
open,high,low,close,volume
|
||||
99,101,98,100,1000
|
||||
102.57761950472302,104.77731091023225,101.25551066110417,103.4552020666134,1019.8669330795061
|
||||
106.10612242808222,108.13914959894458,104.61339756308799,106.64642473395035,1038.941834230865
|
||||
109.26253189460714,110.76487377959927,107.8309272112827,109.33326909627483,1056.4642473395036
|
||||
111.7365376962194,112.90403177129735,110.1528967845943,111.32039085967226,1071.7356090899523
|
||||
113.27609348158748,114.45148509543229,111.29955825219574,112.47494986604055,1084.1470984807897
|
||||
113.7284688053824,115.1642566915892,111.30268842257516,112.73847630878196,1093.2039085967226
|
||||
113.06855035377954,114.55977666009171,110.64086736017657,112.13209366648874,1098.544972998846
|
||||
111.40827542637513,112.72390874531129,109.43899848657534,110.75463180551151,1099.9573603041506
|
||||
108.98459460176909,109.99300155201126,107.76539185209613,108.7737988023383,1097.3847630878195
|
||||
106.12753789513545,107.73969337995807,104.79904459577605,106.41120008059868,1090.929742682568
|
||||
103.21387328427625,105.41662717550601,101.71978916733775,103.92254305856751,1080.849640381959
|
||||
100.61462528040111,103.00209502109563,99.18732582635697,101.57479556705148,1067.546318055115
|
||||
98.64575078243223,100.78188758933494,97.48620160125755,99.62233840816026,1051.5501371821465
|
||||
97.53034002152081,99.46748184049008,96.34710045689485,98.28424227586412,1033.4988150155905
|
||||
97.378063505514,99.16454670333486,95.93821562552817,97.72469882334903,1014.1120008059867
|
||||
98.18385394545021,99.67344281002588,96.54876504706593,98.0383539116416,1005.837414342758
|
||||
99.8438650794075,101.15293363552601,97.93278462060415,99.24185317672267,1025.5541102026832
|
||||
102.1834853863248,103.20029690993537,100.25554360082955,101.27235512444012,1044.2520443294852
|
||||
104.99031673022002,106.32510161131832,102.65835969292533,103.99314457402363,1061.185789094272
|
||||
108.04491654708718,109.54022022493461,105.7105413401633,107.20584501801073,1075.680249530793
|
||||
111.14367593283949,112.56654934841096,109.24526558927202,110.6681390048435,1087.157577241359
|
||||
114.11098793714572,115.26697281350663,112.95942875877287,114.11541363513378,1095.1602073889517
|
||||
116.80109288512898,118.47543335247398,115.61005717653698,117.28439764388199,1099.3691003633464
|
||||
119.09282467975903,121.38046215528227,117.64904116296829,119.93667863849153,1099.616460883584
|
||||
120.88220148856881,123.36781277048146,119.39438848583472,121.87999976774739,1095.8924274663138
|
||||
122.07798667229586,124.2878498649492,120.77557026109272,122.98543345374605,1088.3454655720152
|
||||
122.60397744514097,124.22410945235427,121.57876610123756,123.19889810845086,1077.2764487555987
|
||||
122.40925186267498,123.88697089091687,121.06827005264091,122.5459890808828,1063.126663787232
|
||||
121.48461656761053,122.98099977052848,119.63330909790388,121.12969230082183,1046.4602179413757
|
||||
119.8808727652764,121.29920058454442,117.70285703314954,119.12118485241757,1027.9415498198925
|
||||
117.72299769788953,118.8665240235534,115.60101790940676,116.74454423507063,1008.3089402817496
|
||||
115.21439166809358,116.4131695096543,113.05795434620948,114.2567321877702,1011.6549204850494
|
||||
112.6270381197495,114.07463180365934,110.47704737833695,111.92464106224679,1031.154136351338
|
||||
110.27641646211617,111.76231568498811,108.51535390119264,110.00125312406458,1049.4113351138608
|
||||
108.48360243707184,109.99872116521585,107.18792367213928,108.7030424002833,1065.6986598718788
|
||||
107.530320991091,109.22424173559783,106.49671695482826,108.19063769933508,1079.3667863849153
|
||||
107.61494922421186,109.90155645208623,106.26786689008574,108.55447411796011,1089.8708095811626
|
||||
108.81801012516657,111.30403713029216,107.32068773822765,109.80671474335324,1096.7919672031487
|
||||
111.08434919099572,113.29382811110736,109.67068524069803,111.88016416080967,1099.8543345374605
|
||||
114.22618875818226,115.76972371414958,113.09073586402833,114.63427081999565,1098.9358246623383
|
||||
117.94724565362051,119.15370942824079,116.6612183117217,117.86768208634197,1094.0730556679773
|
||||
121.88395973243564,123.33523703654073,119.88495316810628,121.33623047221137,1085.459890808828
|
||||
125.65653611891825,127.14038418498515,123.29089632531003,124.77474439137693,1073.4397097874114
|
||||
128.92069597346688,130.20955349568973,126.63187762484937,127.92073514707224,1058.4917192891762
|
||||
131.41114890560974,132.45313613345562,129.49585703767033,130.5378442655162,1041.2118485241756
|
||||
132.96978971477444,134.3228744433646,131.08387196585088,132.43695669444105,1022.2889914100246
|
||||
133.5549991814736,135.053120145851,131.99497292310176,133.49309388747918,1002.4775425453357
|
||||
133.2323987581558,135.065460892756,131.8235156308926,133.65657776549278,1017.4326781222982
|
||||
132.1510588175171,134.08480947785137,131.0237176510951,132.95746831142935,1036.647912925193
|
||||
130.5116755897077,132.71696973631924,129.29758425495962,131.50287840157117,1054.402111088937
|
||||
128.53409061924222,130.9222390672229,127.07925728332546,129.46740573130614,1069.9874687593544
|
||||
126.4306172006658,128.5591966352313,124.94895708842891,127.07753652299444,1082.7826469085653
|
||||
124.38927906587094,125.87336879788326,123.1073244542458,124.59141418625812,1092.2775421612807
|
||||
122.56791894474918,123.61827749324543,121.2254215875191,122.27578013601534,1098.093623006649
|
||||
121.09703354508844,122.45602084147426,119.02315927992295,120.38214657630877,1099.9990206550704
|
||||
120.08693553049852,121.58571423995242,117.62555095473105,119.12432966418496,1097.9177729151318
|
||||
119.63399522490424,121.03798192673773,117.25536324735009,118.65934994918358,1091.9328525664675
|
||||
119.82146372498268,120.94065716085713,117.95421275941922,119.07340619529367,1082.2828594968707
|
||||
120.7124947130592,121.93415307848436,119.152517136663,120.37417550208815,1069.3525084777123
|
||||
122.33587608239566,123.94838830624106,120.87761530843784,122.49012753228324,1053.6572918000436
|
||||
124.66785812762632,126.75625008370868,123.18852214765032,125.27691410373268,1035.8229282236828
|
||||
127.61552102482923,129.80523536741393,126.34054904004905,128.53026338263376,1016.5604175448309
|
||||
131.00775897051096,133.06294250948164,129.94904333909741,132.0042268780681,1003.3623047221139
|
||||
134.59892592769242,136.79793765689536,133.234137558996,135.43314928819893,1023.1509825101539
|
||||
138.08766685694894,140.0546941334019,136.58837142074304,138.555398697196,1042.016703682664
|
||||
141.1500141222941,142.5489901806554,139.73776131670974,141.13673737507105,1059.2073514707224
|
||||
143.48228026040917,144.5932922665057,141.8802335303824,142.99124553647894,1074.037588995245
|
||||
144.84649927621132,146.0756620034572,142.76876627418082,143.9979290014267,1085.9161814856498
|
||||
145.1098734724699,146.57143212166807,142.649968595823,144.11152724502116,1094.3695669444105
|
||||
144.27024859045207,145.7471249168318,141.88968005898082,143.36655638536055,1099.060735569487
|
||||
142.46200877506277,143.72992039092952,140.60631434563564,141.8742259615024,1099.8026652716362
|
||||
139.9404686061768,141.00752471999962,138.7454488027266,139.81250491654941,1096.5657776549278
|
||||
137.04703875358243,138.78071046739933,135.67655244818158,137.41022416199849,1089.4791172140503
|
||||
134.16122174198705,136.42630679247307,132.66155074344638,134.9266357939324,1078.8252067375315
|
||||
131.6480122345848,134.02210748888697,130.25415962109273,132.6282548753949,1065.0287840157116
|
||||
129.80997879551026,131.86785162975886,128.70717960530897,130.76505243955756,1048.6398688853799
|
||||
128.85205701193928,130.78472862032595,127.6154547134165,129.54812632180318,1030.3118356745701
|
||||
128.8642014864336,130.59557044803222,127.39947545719488,129.13084441879352,1010.7753652299442
|
||||
129.82321172551153,131.29749357237068,128.12086294416926,129.59514479102842,1009.1906850227682
|
||||
|
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
macd,signal,histogram
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
nan,nan,nan
|
||||
3.553825374871522,4.7567646581597245,-1.2029392832882024
|
||||
2.8208654161048656,4.369584809748753,-1.5487193936438874
|
||||
2.1109014543067843,3.9178481386603594,-1.806946684353575
|
||||
1.4897304373886868,3.4322245984060253,-1.9424941610173385
|
||||
1.0151049910054155,2.9488006769259036,-1.9336956859204881
|
||||
0.7315731385597957,2.5053551692526823,-1.7737820306928866
|
||||
0.6664991548332893,2.137583966368804,-1.4710848115355146
|
||||
0.8276206486027746,1.8755913028155982,-1.0479706542128235
|
||||
1.2023598043004569,1.74094500311257,-0.5385851988121131
|
||||
1.7589500704087442,1.744546016571805,0.014404053836939212
|
||||
2.449277456832604,1.885492304623965,0.563785152208639
|
||||
3.2131824784813148,2.1510303393954353,1.0621521390858795
|
||||
3.9838383370451567,2.5175919389253796,1.466246398119777
|
||||
4.693724820711168,2.9528185152825377,1.7409063054286302
|
||||
5.280664208546995,3.418387653935429,1.8622765546115656
|
||||
5.693379944743711,3.8733861120970854,1.8199938326466256
|
||||
5.896081491642136,4.277925188006096,1.6181563036360398
|
||||
5.871665770714699,4.596673304547816,1.274992466166883
|
||||
5.623249186369037,4.801988480912061,0.821260705456976
|
||||
5.17389335937969,4.876369456605587,0.29752390277410345
|
||||
4.564549053715282,4.814005376027526,-0.2494563223122439
|
||||
3.8504019492156516,4.621284690665152,-0.7708827414495003
|
||||
3.0959466751243525,4.316217087556993,-1.2202704124326402
|
||||
2.369229123514458,3.926819494748486,-1.5575903712340278
|
||||
1.735771359392487,3.488609867677286,-1.7528385082847988
|
||||
1.252721799050505,3.0414322539519296,-1.7887104549014246
|
||||
0.9637532073126067,2.6258964446240656,-1.6621432373114589
|
||||
0.8951642651140048,2.2797500087220537,-1.3845857436080489
|
||||
1.0535329484060725,2.0345065966588574,-0.9809736482527849
|
||||
1.4251313413431745,1.9126315455957208,-0.48750020425254625
|
||||
1.9771541634642489,1.9255360691694265,0.051618094294822336
|
||||
2.6606512771767967,2.072559110770901,0.5880921664058958
|
||||
3.414902230493496,2.34102773471542,1.073874495778076
|
||||
4.17284207727586,2.707390603227508,1.4654514740483515
|
||||
4.867053809684606,3.139323244518928,1.727730565165678
|
||||
5.4357921236225195,3.5986170203396464,1.8371751032828731
|
||||
5.828500438890558,4.044593704049829,1.7839067348407287
|
||||
6.010328361604678,4.437740635560799,1.5725877260438788
|
||||
5.965246063689932,4.743241721186626,1.2220043425033058
|
||||
5.697477387222705,4.934088854393842,0.7633885328288628
|
||||
5.231123664416998,4.9934958163984735,0.23762784801852455
|
||||
4.608011861752942,4.916399025469367,-0.30838716371642505
|
||||
3.883959272298,4.709911074835094,-0.8259518025370935
|
||||
3.123788425025225,4.39268654487312,-1.2688981198478952
|
||||
2.395537519050208,3.993256739708538,-1.59771922065833
|
||||
1.764383551803462,3.547482102127523,-1.7830985503240608
|
||||
1.286820974089835,3.0953498765199856,-1.8085289024301505
|
||||
|
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
rsi
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
46.84518809898699
|
||||
45.82961265424322
|
||||
46.5293990131247
|
||||
49.23903870201344
|
||||
53.518768674122796
|
||||
58.56047460456064
|
||||
63.58342577996474
|
||||
68.07459111891804
|
||||
71.80327260156207
|
||||
74.72559789038102
|
||||
76.88488357198254
|
||||
78.34471541432595
|
||||
79.15131540353094
|
||||
79.31156608926268
|
||||
77.35312513119456
|
||||
73.13439349750769
|
||||
67.51119167055117
|
||||
61.48673113238304
|
||||
55.86675382432369
|
||||
51.14733221714866
|
||||
47.57753664027756
|
||||
45.28036590056008
|
||||
44.36975889174273
|
||||
45.212282377402985
|
||||
48.12434665867438
|
||||
52.61537254620642
|
||||
57.83678169397702
|
||||
62.992663568874654
|
||||
67.57346293490359
|
||||
71.3583982125327
|
||||
74.31265622918312
|
||||
76.4855340725887
|
||||
77.9435594091973
|
||||
78.73329989554925
|
||||
78.85948376472163
|
||||
76.76197022138767
|
||||
72.44443440532005
|
||||
66.78373698621982
|
||||
60.77877328002407
|
||||
55.21662487911296
|
||||
50.57413251002351
|
||||
47.087563552178636
|
||||
44.87458874458458
|
||||
44.050409895373384
|
||||
45.01878876311954
|
||||
48.0601943425273
|
||||
52.64880490307121
|
||||
57.92140340103244
|
||||
63.088714334306665
|
||||
67.65616719708338
|
||||
71.41589642993111
|
||||
74.34074717674663
|
||||
76.4832369420561
|
||||
77.91026866443379
|
||||
78.66702552588708
|
||||
78.75547116040536
|
||||
76.51507736151031
|
||||
72.09088140590961
|
||||
66.3803507173797
|
||||
60.378854393296976
|
||||
54.856911707280055
|
||||
50.27461841837877
|
||||
46.857548898064
|
||||
44.719625963574536
|
||||
43.978649539628535
|
||||
45.06927522550655
|
||||
|
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
sma
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
nan
|
||||
107.082865308575
|
||||
106.96031118542241
|
||||
106.55098952518925
|
||||
105.93612732359576
|
||||
105.21531190077062
|
||||
104.49759506253974
|
||||
103.89175182739567
|
||||
103.49656387805487
|
||||
103.39199568793734
|
||||
103.63205153291037
|
||||
104.23995145016349
|
||||
105.20605706144154
|
||||
106.48873254066868
|
||||
108.01806381828972
|
||||
109.7021037968819
|
||||
111.4350857115261
|
||||
113.10687095991703
|
||||
114.61278745568676
|
||||
115.86297967414018
|
||||
116.79043517866376
|
||||
117.35697064210828
|
||||
117.55664264968355
|
||||
117.41627860650068
|
||||
116.99308032537222
|
||||
116.36951435923494
|
||||
115.64594550958222
|
||||
114.93167153765809
|
||||
114.33515992096163
|
||||
113.9543587765253
|
||||
113.86794744733447
|
||||
114.12830831094557
|
||||
114.75684761770661
|
||||
115.742083334167
|
||||
117.04067079892921
|
||||
118.58127457216008
|
||||
120.2709406179764
|
||||
122.00339961162967
|
||||
123.66855966178939
|
||||
125.16234049131411
|
||||
126.39597061843133
|
||||
127.30391704882051
|
||||
127.84973914282192
|
||||
128.0293437492481
|
||||
127.87135083438908
|
||||
127.43453694566097
|
||||
126.80258487767678
|
||||
126.07660853743191
|
||||
125.36612074013492
|
||||
124.7792507555816
|
||||
124.41308544252024
|
||||
124.34499676870873
|
||||
124.62573040346784
|
||||
125.27487275817427
|
||||
126.27910139046546
|
||||
127.59337505833837
|
||||
129.14495712015346
|
||||
130.83991288220435
|
||||
132.57150050514548
|
||||
134.2297059345968
|
||||
135.71107012897224
|
||||
136.92793074753726
|
||||
137.81625276622648
|
||||
138.34134853563094
|
||||
138.50097632541122
|
||||
138.3255405713923
|
||||
137.87537593786334
|
||||
137.23535780170852
|
||||
|
Reference in New Issue
Block a user