New version merge

This commit is contained in:
Miha Kralj
2024-09-22 17:31:24 -07:00
parent 1b719fa94e
commit d475bcd19a
405 changed files with 56573 additions and 12440 deletions
+198
View File
@@ -0,0 +1,198 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#r "..\src\obj\Debug\QuanTAlib.dll"
#r "nuget:Skender.Stock.Indicators"
using Skender.Stock.Indicators;
using QuanTAlib;
#!csharp
public class Htit : AbstractBase
{
private readonly int _period;
private readonly CircularBuffer _pr, _sp, _dt, _pd, _q1, _i1, _q2, _i2, _re, _im, _sd, _it;
public Htit(int period = 50) : base()
{
_period = period;
_pr = new CircularBuffer(period);
_sp = new CircularBuffer(period);
_dt = new CircularBuffer(period);
_pd = new CircularBuffer(period);
_q1 = new CircularBuffer(period);
_i1 = new CircularBuffer(period);
_q2 = new CircularBuffer(period);
_i2 = new CircularBuffer(period);
_re = new CircularBuffer(period);
_im = new CircularBuffer(period);
_sd = new CircularBuffer(period);
_it = new CircularBuffer(period);
Name = "Htit";
WarmupPeriod = 12; // Minimum required data points
Init();
}
public Htit(object source, int period = 50) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
public override void Init()
{
base.Init();
_pr.Clear();
_sp.Clear();
_dt.Clear();
_pd.Clear();
_q1.Clear();
_i1.Clear();
_q2.Clear();
_i2.Clear();
_re.Clear();
_im.Clear();
_sd.Clear();
_it.Clear();
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_index++;
}
}
protected override double GetLastValid()
{
return _it[^1];
}
protected override double Calculation()
{
ManageState(Input.IsNew);
_pr.Add(Input.Value, Input.IsNew);
if (_index > 6)
{
double adj = (0.075 * _pd[^2]) + 0.54;
// smooth and detrender
_sp.Add(((4 * _pr[^1]) + (3 * _pr[^2]) + (2 * _pr[^3]) + _pr[^4]) / 10, Input.IsNew);
_dt.Add(((0.0962 * _sp[^1]) + (0.5769 * _sp[^3]) - (0.5769 * _sp[^5]) - (0.0962 * _sp[^7])) * adj, Input.IsNew);
// in-phase and quadrature
_q1.Add(((0.0962 * _dt[^1]) + (0.5769 * _dt[^3]) - (0.5769 * _dt[^5]) - (0.0962 * _dt[^7])) * adj, Input.IsNew);
_i1.Add(_dt[^4], Input.IsNew);
// advance the phases by 90 degrees
double jI = ((0.0962 * _i1[^1]) + (0.5769 * _i1[^3]) - (0.5769 * _i1[^5]) - (0.0962 * _i1[^7])) * adj;
double jQ = ((0.0962 * _q1[^1]) + (0.5769 * _q1[^3]) - (0.5769 * _q1[^5]) - (0.0962 * _q1[^7])) * adj;
// phasor addition for 3-bar averaging
_i2.Add(_i1[^1] - jQ, Input.IsNew);
_q2.Add(_q1[^1] + jI, Input.IsNew);
_i2[^1] = (0.2 * _i2[^1]) + (0.8 * _i2[^2]); // smoothing it
_q2[^1] = (0.2 * _q2[^1]) + (0.8 * _q2[^2]);
// homodyne discriminator
_re.Add((_i2[^1] * _i2[^2]) + (_q2[^1] * _q2[^2]), Input.IsNew);
_im.Add((_i2[^1] * _q2[^2]) - (_q2[^1] * _i2[^2]), Input.IsNew);
_re[^1] = (0.2 * _re[^1]) + (0.8 * _re[^2]); // smoothing it
_im[^1] = (0.2 * _im[^1]) + (0.8 * _im[^2]);
// calculate period
_pd.Add(_im[^1] != 0 && _re[^1] != 0
? 2 * Math.PI / Math.Atan(_im[^1] / _re[^1])
: 0, Input.IsNew);
// adjust period to thresholds
_pd[^1] = (_pd[^1] > 1.5 * _pd[^2]) ? 1.5 * _pd[^2] : _pd[^1];
_pd[^1] = (_pd[^1] < 0.67 * _pd[^2]) ? 0.67 * _pd[^2] : _pd[^1];
_pd[^1] = (_pd[^1] < 6.0) ? 6.0 : _pd[^1];
_pd[^1] = (_pd[^1] > 50.0) ? 50.0 : _pd[^1];
// smooth the period
_pd[^1] = (0.2 * _pd[^1]) + (0.8 * _pd[^2]);
_sd.Add((0.33 * _pd[^1]) + (0.67 * _sd[^2]), Input.IsNew);
//check this loop
// smooth dominant cycle period
int dcPeriods = (int)(_sd[^1] + 0.5);
double sumPr = 0;
for (int d = 1; d < dcPeriods+1; d++) //0 -> 5
{
sumPr += _pr[^d];
}
_it.Add(dcPeriods > 0 ? sumPr / dcPeriods : _pr[^1], Input.IsNew);
Console.WriteLine($"{_index}\t {_it[^1]:F2}");
// final indicators
double Trendline, SmoothPrice;
Trendline = _index >= 12 // 12th bar
? ((4 * _it[^1]) + (3 * _it[^2]) + (2 * _it[^3]) + _it[^4]) / 10.0
: _pr[^1];
SmoothPrice = ((4 * _pr[^1]) + (3 * _pr[^2]) + (2 * _pr[^3]) + _pr[^4]) / 10.0;
Value = Trendline;
}
else
{
Value = _pr[^1];
_pd.Add(0, Input.IsNew);
_sp.Add(0, Input.IsNew);
_dt.Add(0, Input.IsNew);
_i1.Add(0, Input.IsNew);
_q1.Add(0, Input.IsNew);
_i2.Add(0, Input.IsNew);
_q2.Add(0, Input.IsNew);
_re.Add(0, Input.IsNew);
_im.Add(0, Input.IsNew);
_sd.Add(0, Input.IsNew);
_it.Add(_pr[^1], Input.IsNew);
}
IsHot = _index >= WarmupPeriod;
return Value;
}
}
#!csharp
Random rnd = new((int)DateTime.Now.Ticks);
GbmFeed feed = new(sigma: 0.5, mu: 0.0);
TBarSeries bars = new(feed);
feed.Add(15);
IEnumerable<Quote> quotes = feed.Select(q => new Quote {
Date = q.Time,
Open = (decimal)q.Open,
High = (decimal)q.High,
Low = (decimal)q.Low,
Close = (decimal)q.Close,
Volume = (decimal)q.Volume
});
Htit ma = new();
TSeries QL = new();
foreach (TBar item in feed) { QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.Select(q => (q.Date, (double)q.Close)).GetHtTrendline().Select(i => i.Trendline.Null2NaN()!);
Console.WriteLine($"Data\tSkend\tQuanTAlib");
for (int i = 8; i < feed.Length; i++)
{
Console.WriteLine($"{i}\t{feed[i].Close,6:F2}\t{SK.ElementAt(i),6:F2}\t{QL[i].Value,6:F2} {Math.Truncate(SK.ElementAt(i)*100)==Math.Truncate(QL[i].Value*100)}");
}
+28
View File
@@ -0,0 +1,28 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#r "nuget: Tulip.NETCore, 0.8.0.1"
#!csharp
using Tulip;
double[] data = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };
int period = 3;
private double[] outdata = new double[data.Count()];
double[][] arrin = new double[][] { data };
double[][] arrout = new double[][] { outdata };
Tulip.Indicators.ema.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i=0; i<arrout[0].Length-1; i++) {
double TU = i<0?double.NaN:arrout[0][i];
Console.WriteLine($"{TU:F2}");
}
#!csharp
arrout[0]
+919
View File
@@ -0,0 +1,919 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
using System.Collections;
using System.Runtime.CompilerServices;
using System.Numerics;
public class CircularBuffer : IEnumerable<double>
{
private readonly double[] _buffer;
private int _start = 0;
private int _size = 0;
public int Capacity { get; }
public int Count => _size;
public CircularBuffer(int capacity)
{
Capacity = capacity;
_buffer = GC.AllocateArray<double>(capacity, pinned: true);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(double item, bool isNew = true)
{
if (_size == 0 || isNew)
{
if (_size < Capacity)
{
_buffer[(_start + _size) % Capacity] = item;
_size++;
}
else
{
_buffer[_start] = item;
_start = (_start + 1) % Capacity;
}
}
else
{
_buffer[(_start + _size - 1) % Capacity] = item;
}
}
public double this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
index = index < 0 ? 0 : (index >= _size ? _size - 1 : index);
return _buffer[(_start + index) % Capacity];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
index = index < 0 ? 0 : (index >= _size ? _size - 1 : index);
_buffer[(_start + index) % Capacity] = value;
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowArgumentOutOfRangeException()
{
throw new ArgumentOutOfRangeException("index", "Index is out of range.");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Newest()
{
if (_size == 0)
return 0;
return _buffer[(_start + _size - 1) % Capacity];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Oldest()
{
if (_size == 0)
ThrowInvalidOperationException();
return _buffer[_start];
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowInvalidOperationException()
{
throw new InvalidOperationException("Buffer is empty.");
}
public Enumerator GetEnumerator() => new(this);
IEnumerator<double> IEnumerable<double>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public struct Enumerator : IEnumerator<double>
{
private readonly CircularBuffer _buffer;
private int _index;
private double _current;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Enumerator(CircularBuffer buffer)
{
_buffer = buffer;
_index = -1;
_current = default;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
if (_index + 1 >= _buffer._size)
return false;
_index++;
_current = _buffer[_index];
return true;
}
public double Current => _current;
object IEnumerator.Current => Current;
public void Reset()
{
_index = -1;
_current = default;
}
public void Dispose() { }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(double[] destination, int destinationIndex)
{
if (_size == 0)
return;
if (_start + _size <= Capacity)
{
Array.Copy(_buffer, _start, destination, destinationIndex, _size);
}
else
{
int firstPartLength = Capacity - _start;
Array.Copy(_buffer, _start, destination, destinationIndex, firstPartLength);
Array.Copy(_buffer, 0, destination, destinationIndex + firstPartLength, _size - firstPartLength);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<double> GetSpan()
{
if (_size == 0)
return ReadOnlySpan<double>.Empty;
if (_start + _size <= Capacity)
{
return new ReadOnlySpan<double>(_buffer, _start, _size);
}
else
{
return new ReadOnlySpan<double>(ToArray());
}
}
public double[] InternalBuffer => _buffer;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<double> GetInternalSpan() => _buffer.AsSpan();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
Array.Clear(_buffer, 0, _buffer.Length);
_start = 0;
_size = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Max()
{
if (_size == 0)
ThrowInvalidOperationException();
return MaxSimd();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Min()
{
if (_size == 0)
ThrowInvalidOperationException();
return MinSimd();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Sum()
{
return SumSimd();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Average()
{
if (_size == 0)
ThrowInvalidOperationException();
return SumSimd() / _size;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double MaxSimd()
{
var span = GetSpan();
var vectorSize = Vector<double>.Count;
var maxVector = new Vector<double>(double.MinValue);
int i = 0;
for (; i <= span.Length - vectorSize; i += vectorSize)
{
maxVector = Vector.Max(maxVector, new Vector<double>(span.Slice(i, vectorSize)));
}
double max = double.MinValue;
for (int j = 0; j < vectorSize; j++)
{
max = Math.Max(max, maxVector[j]);
}
for (; i < span.Length; i++)
{
max = Math.Max(max, span[i]);
}
return max;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double MinSimd()
{
var span = GetSpan();
var vectorSize = Vector<double>.Count;
var minVector = new Vector<double>(double.MaxValue);
int i = 0;
for (; i <= span.Length - vectorSize; i += vectorSize)
{
minVector = Vector.Min(minVector, new Vector<double>(span.Slice(i, vectorSize)));
}
double min = double.MaxValue;
for (int j = 0; j < vectorSize; j++)
{
min = Math.Min(min, minVector[j]);
}
for (; i < span.Length; i++)
{
min = Math.Min(min, span[i]);
}
return min;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double SumSimd()
{
var span = GetSpan();
var vectorSize = Vector<double>.Count;
var sumVector = Vector<double>.Zero;
int i = 0;
for (; i <= span.Length - vectorSize; i += vectorSize)
{
sumVector += new Vector<double>(span.Slice(i, vectorSize));
}
double sum = 0;
for (int j = 0; j < vectorSize; j++)
{
sum += sumVector[j];
}
for (; i < span.Length; i++)
{
sum += span[i];
}
return sum;
}
public double[] ToArray()
{
double[] array = new double[_size];
CopyTo(array, 0);
return array;
}
public void ParallelOperation(Func<double[], int, int, double> operation)
{
const int MinimumPartitionSize = 1024;
if (_size < MinimumPartitionSize)
{
var span = GetSpan();
var array = span.ToArray();
operation(array, 0, array.Length);
return;
}
int partitionCount = Environment.ProcessorCount;
int partitionSize = _size / partitionCount;
if (partitionSize < MinimumPartitionSize)
{
partitionCount = Math.Max(1, _size / MinimumPartitionSize);
partitionSize = _size / partitionCount;
}
var buffer = ToArray();
var results = new double[partitionCount];
Parallel.For(0, partitionCount, i =>
{
int start = i * partitionSize;
int length = (i == partitionCount - 1) ? _size - start : partitionSize;
results[i] = operation(buffer, start, length);
});
}
}
#!csharp
public interface iTValue {
DateTime Time { get; }
double Value { get; }
bool IsNew { get; }
bool IsHot { get; }
}
public readonly record struct TValue(DateTime Time, double Value, bool IsNew = true, bool IsHot = true) : iTValue {
public DateTime Time { get; init; } = Time;
public double Value { get; init; } = Value;
public bool IsNew { get; init; } = IsNew;
public bool IsHot { get; init; } = IsHot;
public DateTime t => Time;
public double v => Value;
public TValue() : this(DateTime.UtcNow, 0) { }
public TValue(double value, bool isNew=true, bool isHot=true) : this(DateTime.UtcNow, value, IsNew:isNew, IsHot:isHot) { }
public static implicit operator double(TValue tv) => tv.Value;
public static implicit operator DateTime(TValue tv) => tv.Time;
public static implicit operator TValue(double value) => new TValue(DateTime.UtcNow, value);
public override string ToString() => $"[{Time:yyyy-MM-dd HH:mm:ss}, {Value:F2}, IsNew: {IsNew}, IsHot: {IsHot}]";
}
public delegate void ValueSignal(object source, in ValueEventArgs args);
public class ValueEventArgs : EventArgs {
public TValue Tick { get; }
public ValueEventArgs(TValue value) { Tick = value; }
}
public class TSeries : List<TValue> {
private readonly TValue Default = new(DateTime.MinValue, double.NaN);
public IEnumerable<DateTime> t => this.Select(item => item.t);
public IEnumerable<double> v => this.Select(item => item.v);
public TValue Last => Count > 0 ? this[^1] : Default;
public TValue First => Count > 0 ? this[0] : Default;
public int Length => Count;
public string Name { get; set; }
public event ValueSignal Pub = delegate { };
public TSeries() { this.Name = "Data"; }
public TSeries (object source) : this() {
var pubEvent = source.GetType().GetEvent("Pub");
if (pubEvent != null) {
/*
var nameProperty = source.GetType().GetProperty("Name");
if (nameProperty != null) {
Name = nameProperty.GetValue(nameProperty)?.ToString()!;
}
*/
pubEvent.AddEventHandler(source, new ValueSignal(Sub));
}
}
public static explicit operator List<double>(TSeries series) => series.Select(item => item.Value).ToList();
public static explicit operator double[](TSeries series) => series.Select(item => item.Value).ToArray();
public new virtual void Add(TValue tick) {
if (tick.IsNew) { base.Add(tick); }
else { this[^1] = tick; }
Pub?.Invoke(this, new ValueEventArgs(tick));
}
public virtual void Add(DateTime Time, double Value, bool IsNew=true, bool IsHot=true) => this.Add(new TValue(Time, Value, IsNew, IsHot));
public virtual void Add(double Value, bool IsNew=true, bool IsHot=true) => this.Add(new TValue(DateTime.UtcNow, Value, IsNew, IsHot));
public void Add(IEnumerable<double> values) {
var valueList = values.ToList();
int count = valueList.Count;
DateTime startTime = DateTime.UtcNow - TimeSpan.FromHours(count);
for (int i = 0; i < count; i++) {
this.Add(startTime, valueList[i]);
startTime = startTime.AddHours(1);
}
}
public void Add(TSeries series) {
if (series == this) {
// If adding itself, create a copy to avoid modification during enumeration
var copy = new TSeries { Name = this.Name };
copy.AddRange(this);
AddRange(copy);
} else {
AddRange(series);
}
}
public new virtual void AddRange(IEnumerable<TValue> collection) {
foreach (var item in collection) {
Add(item);
}
}
public void Sub(object source, in ValueEventArgs args) { Add(args.Tick); }
}
#!csharp
TValue a = new(10.0);
TSeries ll = new();
ll.Add(a);
ll.Add(10);
TSeries ll1 = new();
ll.Add(new double[]{1, 2, 3, 4});
ll.Add(new List<double>{1, 2, 3, 4});
ll.Add(ll);
display((double[])ll);
#!csharp
public interface iTBar {
DateTime Time { get; }
double Open { get; }
double High { get; }
double Low { get; }
double Close { get; }
double Volume { get; }
bool IsNew { get; }
}
public readonly record struct TBar(DateTime Time, double Open, double High, double Low, double Close, double Volume, bool IsNew = true) :iTBar {
public DateTime Time { get; init; } = Time;
public double Open { get; init; } = Open;
public double High { get; init; } = High;
public double Low { get; init; } = Low;
public double Close { get; init; } = Close;
public double Volume { get; init; } = Volume;
public bool IsNew { get; init; } = IsNew;
public double HL2 => (High + Low) * 0.5;
public double OC2 => (Open + Close) * 0.5;
public double OHL3 => (Open + High + Low) /3;
public double HLC3 => (High + Low + Close) /3;
public double OHLC4 => (Open + High + Low + Close) * 0.25;
public double HLCC4 => (High + Low + Close + Close) * 0.25;
public TBar() : this(DateTime.UtcNow, 0, 0, 0, 0, 0) { }
public TBar(double Open, double High, double Low, double Close, double Volume, bool IsNew = true) : this(DateTime.UtcNow, Open, High, Low, Close, Volume, IsNew) { }
// when TBar casts to double, it returns its Close
public static implicit operator double(TBar bar) => bar.Close;
public static implicit operator DateTime(TBar tv) => tv.Time;
// castings for sloppy people - a single double injected into a TBar, and a single TValue injected into a TBar
public TBar (double value) : this(Time: DateTime.UtcNow, Open: value, High: value, Low: value, Close: value, Volume: value, IsNew: true) {}
public TBar (TValue value) : this(Time: value.Time, Open: value.Value, High: value.Value, Low: value.Value, Close: value.Value, Volume: value.Value, IsNew: value.IsNew) {}
public override string ToString() => $"[{Time:yyyy-MM-dd HH:mm:ss}: O={Open:F2}, H={High:F2}, L={Low:F2}, C={Close:F2}, V={Volume:F2}]";
}
public delegate void BarSignal(object source, in TBarEventArgs args);
public class TBarEventArgs : EventArgs {
public TBar Bar { get; }
public TBarEventArgs(TBar bar) { Bar = bar; }
}
public class TBarSeries : List<TBar> {
private readonly TBar Default = new(DateTime.MinValue, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN);
public TSeries Open;
public TSeries High;
public TSeries Low;
public TSeries Close;
public TSeries Volume;
public TBar Last => Count > 0 ? this[^1] : Default;
public TBar First => Count > 0 ? this[0] : Default;
public int Length => Count;
public string Name { get; set; }
public event BarSignal Pub = delegate { };
public TBarSeries() {
this.Name = "Bar";
Open = new();
High = new();
Low = new();
Close = new();
Volume = new();
}
public TBarSeries (object source) : this() {
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
}
public new virtual void Add(TBar bar) {
if (bar.IsNew) { base.Add(bar); }else { this[^1] = bar; }
Pub?.Invoke(this, new TBarEventArgs(bar));
Open.Add(bar.Time, bar.Open, IsNew: bar.IsNew, IsHot: true);
High.Add(bar.Time, bar.High, IsNew: bar.IsNew, IsHot: true);
Low.Add(bar.Time, bar.Low, IsNew: bar.IsNew, IsHot: true);
Close.Add(bar.Time, bar.Close, IsNew: bar.IsNew, IsHot: true);
Volume.Add(bar.Time, bar.Volume, IsNew: bar.IsNew, IsHot: true);
}
public void Add(DateTime Time, double Open, double High, double Low, double Close, double Volume, bool IsNew = true) =>
this.Add(new TBar(Time, Open, High, Low, Close, Volume, IsNew));
public void Add(double Open, double High, double Low, double Close, double Volume, bool IsNew = true) =>
this.Add(new TBar(DateTime.Now, Open, High, Low, Close, Volume, IsNew));
public void Add(TBarSeries series) {
if (series == this) {
// If adding itself, create a copy to avoid modification during enumeration
var copy = new TBarSeries { Name = this.Name };
copy.AddRange(this);
AddRange(copy);
} else {
AddRange(series);
}
}
public new virtual void AddRange(IEnumerable<TBar> collection) {
foreach (var item in collection) {
Add(item);
}
}
public void Sub(object source, in TBarEventArgs args) {
Add(args.Bar);
}
}
#!csharp
TBarSeries ll = new();
ll.Add(1,2,3,4,5);
ll.Add(1,2,3,4,5);
ll.Add(1,2,3,4,5);
ll.Add(ll);
//ll.Add(a);
//ll.Add(10);
//TSeries ll1 = new();
//ll.Add(new double[]{1, 2, 3, 4});
//ll.Add(new List<double>{1, 2, 3, 4});
//ll.Add(ll);
display(ll.Open.Last.Value);
#!csharp
using System;
using System.Collections.Generic;
using System.CommandLine.Invocation;
public abstract class AbstractBase : iTValue
{
public DateTime Time { get; set; }
public double Value { get; set; }
public bool IsNew { get; set; }
public bool IsHot { get; set; }
public TValue Input { get; set; }
public TValue Tick => new(Time, Value, IsNew, IsHot); // Stores the current value of indicator
public event ValueSignal Pub = delegate { }; // Publisher of generated values
protected int _index; //tracking the position of output
protected double _lastValidValue;
// other _internal vars defined here
protected AbstractBase()
{ //add parameters into constructor
}
public void Sub(object source, in ValueEventArgs args) => Calc(args.Tick);
public virtual void Init()
{
_index = 0;
_lastValidValue = 0;
}
public virtual TValue Calc(TValue input)
{
Input = input;
if (double.IsNaN(input.Value) || double.IsInfinity(input.Value))
{
return Process(new TValue(input.Time, GetLastValid(), input.IsNew, input.IsHot));
}
this.Value = Calculation();
return Process(new TValue(Time: Input.Time, Value: this.Value, IsNew: Input.IsNew, IsHot: this.IsHot));
}
protected virtual double GetLastValid()
{
// should return last valid value
return _lastValidValue;
}
protected abstract void ManageState(bool isNew);
protected abstract double Calculation();
protected virtual TValue Process(TValue value)
{
this.Time = value.Time;
this.Value = value.Value;
this.IsNew = value.IsNew;
this.IsHot = value.IsHot;
Pub?.Invoke(this, new ValueEventArgs(value));
return value;
}
}
#!csharp
using System;
public class EmaCalc : AbstractBase
{
private readonly int _period;
private CircularBuffer _sma;
private double _lastEma, _p_lastEma;
private double _k, _e, _p_e;
private bool _isInitialized, _useSma;
public EmaCalc(int period, bool useSma = true) : base()
{
if (period < 1) {
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
_period = period;
_useSma = useSma;
_sma = new(period);
Init();
}
public EmaCalc(object source, int period, bool useSma = true) : this(period, useSma)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
public override void Init()
{
base.Init();
_k = 2.0 / (_period + 1);
_e = 1.0;
_lastEma = 0;
_isInitialized = false;
_sma = new(_period);
}
protected override void ManageState(bool isNew) {
if (isNew) {
_p_lastEma = _lastEma;
_p_e = _e;
_index++;
} else {
_lastEma = _p_lastEma;
_e = _p_e;
}
}
protected override double GetLastValid() {
return _lastEma;
}
protected override double Calculation() {
double result, _ema;
ManageState(Input.IsNew);
// when _UseSma == true, use SMA calculation until we have enough data points
if (!_isInitialized && _useSma) {
_sma.Add(Input.Value, Input.IsNew);
_ema = _sma.Average();
result = _ema;
if (_index >= _period) {
_isInitialized = true;
}
} else {
// dunamic k when within period; (index is zero-based, therefore +2)
double _dk = (_index +1 >= _period) ? _k : 2.0 / (_index + 2);
// compensator for early ema values
_e = (_e > 1e-10) ? (1 - _dk) * _e : 0;
_ema = _dk * (Input.Value - _lastEma) + _lastEma;
// _useSma decides if we use compensator or not
result = (_useSma || _e == 0)? _ema : _ema / (1 - _e);
}
_lastEma = _ema;
IsHot = _index >= _period;
return result;
}
}
#!csharp
double[] input = new[]{1.0, 2,3,4,5};
TSeries mm = new();
mm.Add(input);
mm.Display();
#!csharp
public class Convolution : AbstractBase
{
private readonly double[] _kernel;
private readonly int _kernelSize;
private CircularBuffer _buffer;
private double[] _normalizedKernel;
public Convolution(double[] kernel)
{
if (kernel == null || kernel.Length == 0)
{
throw new ArgumentException("Kernel must not be null or empty.", nameof(kernel));
}
_kernel = kernel;
_kernelSize = kernel.Length;
_buffer = new CircularBuffer(_kernelSize);
_normalizedKernel = new double[_kernelSize];
Init();
}
public Convolution(object source, double[] kernel) : this(kernel)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
private void Init()
{
_index = 0;
_lastValidValue = 0;
Array.Copy(_kernel, _normalizedKernel, _kernelSize);
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
protected override double GetLastValid()
{
return _lastValidValue;
}
protected override double Calculation()
{
ManageState(Input.IsNew);
_buffer.Add(Input.Value, Input.IsNew);
// Normalize kernel on each calculation until buffer is full
if (_index <= _kernelSize)
{
NormalizeKernel();
}
double result = ConvolveBuffer();
IsHot = _index >= _kernelSize;
return result;
}
private void NormalizeKernel()
{
int activeLength = Math.Min(_index, _kernelSize);
double sum = 0;
// Calculate the sum of the active kernel elements
for (int i = 0; i < activeLength; i++)
{
sum += _kernel[i];
}
// Normalize the kernel or set equal weights if the sum is zero
double normalizationFactor = (sum != 0) ? sum : activeLength;
for (int i = 0; i < activeLength; i++)
{
_normalizedKernel[i] = _kernel[i] / normalizationFactor;
}
// Set the rest of the normalized kernel to zero
Array.Clear(_normalizedKernel, activeLength, _kernelSize - activeLength);
}
private double ConvolveBuffer()
{
double sum = 0;
var bufferSpan = _buffer.GetSpan();
int activeLength = Math.Min(_index, _kernelSize);
for (int i = 0; i < activeLength; i++)
{
sum += bufferSpan[activeLength - 1 - i] * _normalizedKernel[i];
}
return sum;
}
}
#!csharp
public class Wma : AbstractBase
{
private readonly int _period;
private readonly Convolution _convolution;
public Wma(int period)
{
if (period < 1)
{
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
}
_period = period;
_convolution = new Convolution(GenerateWmaKernel(_period));
Init();
}
public Wma(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
private static double[] GenerateWmaKernel(int period)
{
double[] kernel = new double[period];
double weightSum = period * (period + 1) / 2.0;
for (int i = 0; i < period; i++)
{
kernel[i] = (period - i) / weightSum;
}
return kernel;
}
private new void Init()
{
base.Init();
_convolution.Init();
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
protected override double GetLastValid()
{
return _lastValidValue;
}
protected override double Calculation()
{
ManageState(Input.IsNew);
// Use Convolution for calculation
TValue convolutionResult = _convolution.Calc(Input);
double result = convolutionResult.Value;
IsHot = _index >= _period;
return result;
}
}
#!csharp
TSeries input = new();
double[] kernel = new[]{4.0,3,2,1};
Wma cc = new(input, 5);
TSeries output = new(cc);
input.Add(new double[]{1.0,2,3,4,5,6,7,8});
display((double[])output);
+82
View File
@@ -0,0 +1,82 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#r "..\lib\obj\Debug\QuanTAlib.dll"
using QuanTAlib;
QuanTAlib.Formatters.Initialize();
#!csharp
TSeries Spike = new() { 0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
TSeries Impulse = new() {0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 };
TSeries Triangle = new() {0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2 };
TSeries Sawtooth = new() { 0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
TSeries Sine = new() {0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0.39,0.56,0.72,0.84,0.93,0.99,1,0.97,0.91,0.81,0.68,0.52,0.33,0.14,-0.06,-0.26,-0.44,-0.61,-0.76,-0.87,-0.95,-0.99,-1,-0.96,-0.88,-0.77,-0.63,-0.46,-0.28,-0.08,0.12,0.31,0.49,0.66,0.79,0.9,0.97,1,0.99,0.94,0.85,0.73,0.58,0.41,0.22,0.02,-0.17,-0.37,-0.54,-0.7,-0.83,-0.92,-0.98,-1,-0.98,-0.92,-0.82,-0.69,-0.54,-0.36,-0.17,0.03,0.23,0.42,0.59,0.74 };
TSeries Chirp = new() {0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0.93,0.27,-0.59,-1,-0.71,0.05,0.75,1,0.67,0,-0.67,-0.99,-0.85,-0.34,0.31,0.81,1,0.82,0.35,-0.22,-0.71,-0.98,-0.95,-0.66,-0.2,0.31,0.72,0.96,0.98,0.78,0.43,-0.01,-0.43,-0.77,-0.96,-0.99,-0.85,-0.58,-0.23,0.16,0.51,0.79,0.95,1,0.92,0.73,0.47,0.15,-0.17,-0.47,-0.72,-0.9,-0.99,-0.99,-0.9,-0.74,-0.52,-0.26,0.01,0.28,0.53,0.73,0.88,0.97,1,0.97 };
TSeries White = new() { -0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,0.03,-0.4,-0.47,0.19,-0.4,-0.23,0.31,0.41,0.19,0.16,-0.5,-0.31,-0.21,0.25,0.18,-0.48,-0.1,0.38,0.29,-0.38,-0.08,-0.21,0.34,0.01,-0.46,0.28,-0.48,0.11,0.02,-0.37,0.19,-0.2,0.1,0.24,0.08,-0.22,-0.12,0.15,0.36,-0.43,-0.03,-0.32,0.45,-0.5,-0.04,-0.04,-0.08,-0.18,0.13,-0.33,-0.19,0.36,-0.39,0.2,-0.31,0.28,-0.13,-0.07,-0.29,0.37,0.03,-0.25,-0.06,-0.3,-0.08,-0.09};
TSeries Gauss = new() { -0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,0,0.03,0.11,-0.1,-0.43,-0.08,0.36,-0.04,-0.04,-0.21,-0.3,0.26,0.2,0.28,0.2,0.27,-0.01,-0.1,-0.23,-0.13,-0.41,-0.23,-0.07,-0.21,0.32,-0.18,-0.48,0.3,0.46,-0.2,0.52,-0.81,-0.25,-0.21,-0.12,-0.18,0.18,0.52,0.29,0.44,0.18,-1.2,0.38,0.24,0.06,0.28,0.34,0.3,-0.13,0.19,-0.5,0.59,-0.36,0.22,-0.23,0.24,0.39,0.13,-0.33,-0.57,-0.23,0.49,-0.13,0.76,0.59,0.61};
TSeries B = new() { -0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0,-0.28,0.41,-0.54,0.65,-0.75,0.84,-0.91,0.96,-0.99,1,-0.99,0.96,-0.92,0.85,-0.77,0.67,-0.56,0.44,-0.3,0.17,-0.03,-0.11,0.25,-0.39,0.51,-0.63,0.73,-0.82,0.89,-0.95,0.98,-1,0.99,-0.97,0.93,-0.86,0.78,-0.69,0.58,-0.46,0.33,-0.19,0.05,0.09,-0.23,0.36,-0.49,0.61,-0.71,0.81,-0.88,0.94,-0.98,1,-1,0.98,-0.94,0.88,-0.8,0.71,-0.6,0.48,-0.35,0.22,-0.08,-0.06};
TSeries HF = new() { -0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,0,0.14,-0.76,-0.96,-0.28,0.66,0.99,0.41,-0.54,-1,-0.54,0.42,0.99,0.65,-0.29,-0.96,-0.75,0.15,0.91,0.84,-0.01,-0.85,-0.91,-0.13,0.76,0.96,0.27,-0.66,-0.99,-0.4,0.55,1,0.53,-0.43,-0.99,-0.64,0.3,0.96,0.75,-0.16,-0.92,-0.83,0.02,0.85,0.9,0.12,-0.77,-0.95,-0.26,0.67,0.99,0.4,-0.56,-1,-0.52,0.44,0.99,0.64,-0.3,-0.97,-0.74,0.17,0.92,0.83,-0.03,-0.86};
TSeries ImpulseHF = new() { -0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0,0,0.05,-0.25,-0.32,-0.09,0.22,0.33,0.14,-0.18,-0.33,-0.18,0.14,0.33,0.22,-0.1,-0.32,-0.25,0.05,0.3,0.28,0,-0.28,-0.3,-0.04,0.25,0.32,0.09,-0.22,-0.33,-0.13,0.18,0.33,0.18,0.86,0.67,0.79,1.1,1.32,1.25,0.95,0.69,0.72,1.01,1.28,1.3,1.04,0.74,0.68,0.91,1.22,1.33,1.13,0.81,0.67,0.83,1.15,1.33,1.21,0.9,0.68,0.75,1.06,1.31,1.28,0.99,0.71};
TSeries SawtoothHF = new() { -0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0,0,2.7,-0.8,-0.8,3.6,9.3,11.95,10.05,6.3,5,8.3,14.1,17.95,17.25,13.55,11.2,13.25,18.75,23.55,24.2,20.95,17.75,18.45,23.35,28.8,30.8,28.35,24.7,24.05,28,33.75,37,35.65,31.85,28.05,-3.2,1.5,4.8,3.75,-0.8,-4.6,-4.15,0.1,4.25,4.5,0.6,-3.85,-4.75,-1.3,3.35,4.95,2,-2.8,-5,-2.6,2.2,4.95,3.2,-1.5,-4.85,-3.7,0.85,4.6,4.15,-0.15,-4.3};
TSeries SineG = new() { -0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0,0,0.59,0.83,0.74,0.5,0.91,1.36,0.93,0.87,0.6,0.38,0.78,0.53,0.42,0.14,0.01,-0.45,-0.71,-0.99,-1,-1.36,-1.22,-1.07,-1.17,-0.56,-0.95,-1.11,-0.16,0.18,-0.28,0.64,-0.5,0.24,0.45,0.67,0.72,1.15,1.52,1.28,1.38,1.03,-0.47,0.96,0.65,0.28,0.3,0.17,-0.07,-0.67,-0.51,-1.33,-0.33,-1.34,-0.78,-1.21,-0.68,-0.43,-0.56,-0.87,-0.93,-0.4,0.52,0.1,1.18,1.18,1.35};
TSeries ChirpG = new() { 0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,1.3,0.3,-0.48,-1.1,-1.14,-0.03,1.11,0.96,0.63,-0.21,-0.97,-0.73,-0.65,-0.06,0.51,1.08,0.99,0.72,0.12,-0.35,-1.12,-1.21,-1.02,-0.87,0.12,0.13,0.24,1.26,1.44,0.58,0.95,-0.82,-0.68,-0.98,-1.08,-1.17,-0.67,-0.06,0.06,0.6,0.69,-0.41,1.33,1.24,0.98,1.01,0.81,0.45,-0.3,-0.28,-1.22,-0.31,-1.35,-0.77,-1.13,-0.5,-0.13,-0.13,-0.32,-0.29,0.3,1.22,0.75,1.73,1.59,1.58};
TSeries Complex = new() { 175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.44,176.27,176.04,176.99,175.49,175.68,174.34,176.4,174.05,174.4,174.2,176.16,175,177.72,174.33,176.96,174.62,174.76,170.9,171.12,171.05,170.01,169.24,172.64,171.96,175.72,174.16,175.81,177.3,178.38,176.75,177.19,175.55,178.49,176.52,178.45,178.04,178.25,177.8,176.97,172.94,174.92,173.98,172.29,171.19,172.54,172.11,175.32,175.63,176.65,173.8,176.04,172.74,175.24,171.84,171.54,172.17,171.85,172.38,170.78,173.49,173.69,171.71,174.38,173.99,174.83};
TSeries Market = new() { 68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,67.75,67.75,72.75,74.75,72.25,71.25,71.75,72.75,77.75,76,76,76,74.75,75.5,74.75,73.75,74,74.75,72.25,72.5,72.25,74.5,74.75,75.75,75.75,75.75,74.25,73.75,74.75,72,71.75,72.5,72.25,71,72,71.75,71.75,73.25,72.5,73.75,74,76.75,75.75,75,75.75,74.5,74.25,73.5,71.75,70.5,69,70.5,70,68.75,67.25,68.5,70.75,70,70.5,68.25,68.25,68.25,63.75,64.25};
#!csharp
#r "nuget: ScottPlot"
using ScottPlot;
using Microsoft.DotNet.Interactive.Formatting;
Formatter.Register(typeof(ScottPlot.Plot), (p, w) =>
w.Write(((ScottPlot.Plot)p).GetSvgXml(600, 300)), HtmlFormatter.MimeType);
#!csharp
TSeries ma1 = Spike;
TSeries out1 = new();
Ema calc1 = new(10);
foreach (var value in ma1) { out1.Add(calc1.Calc(value)); }
double[] gma1 = ma1.v.ToArray()[52..];
double[] gsig1 = out1.v.ToArray()[52..];
TSeries ma2 = Impulse;
TSeries out2 = new();
Ema calc2 = new(10);
foreach (var value in ma2) { out2.Add(calc2.Calc(value)); }
double[] gma2 = ma2.v.ToArray()[52..];
double[] gsig2 = out2.v.ToArray()[52..];
#!csharp
Plot plt1 = new();
var p1a = plt1.Add.Signal(gma1); p1a.Color = ScottPlot.Colors.Red; p1a.LineWidth = 2;
var p1b = plt1.Add.Signal(gsig1); p1b.Color = ScottPlot.Colors.Blue; p1b.LineWidth = 3;
plt1.Title("Spike - EMA(10)");
Plot plt2 = new();
var p2a = plt2.Add.Signal(gma2); p2a.Color = ScottPlot.Colors.Red; p2a.LineWidth = 2;
var p2b = plt2.Add.Signal(gsig2); p2b.Color = ScottPlot.Colors.Blue; p2b.LineWidth = 3;
plt2.Title("Impulse - EMA(10)");
plt1.Display();
plt2.Display();
#!csharp
#r "nuget: Plotly.net.Interactive"
#r "nuget: Plotly.NET.CSharp"
using Plotly.NET.Interactive;
using Plotly.NET.CSharp;
#!csharp
var ch1 = Chart.Line<int, double, string>( x: Enumerable.Range(0,gsig.Count()), y: gsig, Name: "signal");
var ch2 = Chart.Line<int, double, string>( x: Enumerable.Range(0,gma.Count()), y: gma);
Chart.Combine(new[] {ch1,ch2}).Display();
+125
View File
@@ -0,0 +1,125 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#r "..\src\obj\Debug\QuanTAlib.dll"
#r "nuget:Skender.Stock.Indicators"
using Skender.Stock.Indicators;
using QuanTAlib;
QuanTAlib.Formatters.Initialize();
#!csharp
GbmFeed gbm = new();
EmaCalc ema1 = new(gbm.Close, 10, useSma: false);
EmaCalc ema2 = new(gbm.Close, 10, useSma: true);
TValSeries res1 = new(ema1);
TValSeries res2 = new(ema2);
gbm.Add(50);
List<double> mse1 = new();
List<double> mse2 = new();
for (int i=0; i< gbm.Length; i++) {
double v= gbm.Close[i].Value;
double e1 = res1[i].Value;
mse1.Add((e1-v)*(e1-v));
double e2 = res2[i].Value;
mse2.Add((e2-v)*(e2-v));
//Console.WriteLine($"{i,3} {mse1.Average(),10:F4} {mse2.Average(),10:F4}");
}
Console.WriteLine($"{mse2.Average()-mse1.Average(),10:F8}");
#!csharp
display(res1);
#!csharp
GbmFeed gbm = new();
EmaCalc ema1 = new(gbm.Close, 10, useSma: false);
EmaCalc ema2 = new(gbm.Close, 10, useSma: true);
TValSeries res1 = new(ema1);
TValSeries res2 = new(ema2);
gbm.Add(30);
IEnumerable<Quote> quotes = gbm.Close.Select(item => new Quote { Date = item.Time, Close = (decimal)item.Value });
var SkResults = quotes.GetEma(10).Select(i => i.Ema.Null2NaN()!);
for (int i=0; i< gbm.Length; i++) {
Console.WriteLine($"{i,3} {gbm.Close[i].Value,6:F2} {res1[i].Value,10:F4} {res2[i].Value,10:F4} {SkResults.ElementAt(i),10:F4}");
}
#!csharp
TValSeries test = new();
EmaCalc ma1 = new(test, 7, true);
TValSeries res1 = new(ma1);
EmaCalc ma2 = new(test, 7, false);
TValSeries res2 = new(ma2);
test.Add(new[]{1.0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0});
for (int i=0; i<res1.Count; i++) {
Console.WriteLine($"{i,2} {test[i].Value,7:F4} {res1[i].Value,7:F4} {res2[i].Value,7:F4}");
}
#!csharp
TValSeries test = new();
EmaCalc ma = new(test,3);
TValSeries result = new();
for (int i=1; i<10; i++) {
test.Add(new TValue(DateTime.Now, (double)i, true, true));
result.Add(ma.Tick);
}
display(result);
#!csharp
TValSeries test = new();
SmaCalc ma = new(test,7);
TValSeries result = new(ma);
test.Add(new[]{81.59, 81.06, 82.87, 83.00, 83.61, 83.15, 82.84, 83.99, 84.55, 84.36, 85.53, 86.54, 86.89, 87.77, 87.29});
//test.Add(new[]{1.0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0});
display(result);
#!csharp
TValue test = new(DateTime.Today, 100, IsHot: false);
TValSeries pub = new();
TValSeries sub = new(pub);
pub.Add(test);
pub.Add(test);
pub.Add(2, true);
pub.Add(DateTime.Today, 123.1234214234, IsHot: true);
display(sub);
display(test);
#!csharp
TBar test = new(DateTime.Now, double.NaN,1,2,3,400.1234);
TBarSeries source = new();
TValSeries target = new(source.Close);
source.Add(new TBar(DateTime.Now,1,2,3,4,125, true));
source.Add(new TBar(DateTime.Now,2,1,5,2,1312, true));
source.Add(test);
source.Name = "MSFT";
display(source);
display(test)
#!csharp
#r "nuget:Skender.Stock.Indicators"
using Skender.Stock.Indicators;
+63
View File
@@ -0,0 +1,63 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#r "..\lib\obj\Debug\QuanTAlib.dll"
using QuanTAlib;
QuanTAlib.Formatters.Initialize();
#!csharp
public class Ema {
double lastema;
double k, extra;
int i, p;
public Ema(int p) {
k = 1/((double) p+1);
extra = 1;
lastema = 0;
}
public double Calc(double value) {
extra = (1 - k) * extra;
double ema = k * (value - lastema) + lastema;
lastema = ema;
return ema / (1 - extra);
}
}
#!csharp
public class Ema {
private double smooth, k;
private double extra;
private int i, p;
public Ema(int period) {
p = period;
k = 1.0 / (p + 1);
extra = 1;
smooth = 0;
i = 0;
}
public double Calc(double value) {
i++;
k = 1/((double)Math.Min(p,i)+1);
extra *= (1-k);
smooth = k * (value - smooth) + smooth;
return extra < 1e-10 ? smooth : smooth / (1 - extra);
}
}
#!csharp
Ema ma = new(3);
double[] input = new[]{1.0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0};
for (int i=0; i<input.Length; i++) {
double output = ma.Calc(input[i]);
Console.WriteLine($" {output:F3}");
}
+229
View File
@@ -0,0 +1,229 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#r "nuget: ScottPlot"
using ScottPlot;
using Microsoft.DotNet.Interactive.Formatting;
Formatter.Register(typeof(ScottPlot.Plot), (p, w) =>
w.Write(((ScottPlot.Plot)p).GetSvgXml(600, 300)), HtmlFormatter.MimeType);
#!csharp
static double[] CalculateEmaWeights(int period, int barCount)
{
double[] weights = new double[barCount];
double alpha = 2.0 / (period + 1);
double weightSum = 0;
for (int i = 0; i < barCount; i++)
{
weights[i] = Math.Pow(1 - alpha, i) * alpha;
weightSum += weights[i];
}
for (int i = 0; i < barCount; i++)
{
weights[i] /= weightSum;
}
return weights;
}
#!csharp
Plot plt = new();
double[] weights = CalculateEmaWeights(10, 30);
var bar = plt.Add.Bars(weights);
plt.Add.Annotation("EMA(10) Weights Chart", Alignment.UpperRight);
var vline = plt.Add.VerticalLine(10.5, width: 1, ScottPlot.Color.FromColor(System.Drawing.Color.Black));
plt.Display();
#!csharp
#r "..\lib\obj\Debug\QuanTAlib.dll"
using QuanTAlib;
QuanTAlib.Formatters.Initialize();
#!csharp
TSeries Spike = new() { 0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
TSeries SpikeJMA = new() {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-0.000552258,-0.000634509,-0.000546757,-0.000418793,-0.000300729,-0.000207311,-0.000138943,-9.12206E-05,-5.89537E-05,-3.76301E-05,-2.3779E-05,-1.49021E-05,-9.27419E-06,-5.73755E-06,-3.53147E-06,-2.16396E-06,-1.32082E-06,-8.03405E-07,-4.87171E-07,-2.94594E-07,-1.77697E-07,-1.06942E-07,-6.42273E-08,-3.85007E-08,-2.3039E-08,-1.37646E-08,-8.21143E-09,-4.89192E-09,-2.91062E-09,-1.72971E-09,-1.02679E-09,-6.08884E-10,0.57216502,0.329278183,0.111882943,0.02038988,-0.00579442,-0.009287974,-0.007184303,-0.004666439,-0.002864099,-0.001904733,-0.001310906,-0.000931811,-0.000671491,-0.000485478,-0.000348532,-0.000247325,-0.00017322,-0.000119743,-8.17596E-05,-5.51943E-05,-3.68781E-05,-2.44116E-05,-1.60241E-05,-1.04391E-05,-6.75421E-06,-4.34304E-06,-2.77694E-06,-1.76649E-06,-1.11846E-06,-7.05115E-07,-4.42777E-07,-2.77032E-07,-1.72747E-07};
TSeries Impulse = new() {0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 };
TSeries ImpulseJMA = new() {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-0.000552258,-0.000634509,-0.000546757,-0.000418793,-0.000300729,-0.000207311,-0.000138943,-9.12206E-05,-5.89537E-05,-3.76301E-05,-2.3779E-05,-1.49021E-05,-9.27419E-06,-5.73755E-06,-3.53147E-06,-2.16396E-06,-1.32082E-06,-8.03405E-07,-4.87171E-07,-2.94594E-07,-1.77697E-07,-1.06942E-07,-6.42273E-08,-3.85007E-08,-2.3039E-08,-1.37646E-08,-8.21143E-09,-4.89192E-09,-2.91062E-09,-1.72971E-09,-1.02679E-09,-6.08884E-10,0.57216502,0.901443203,1.013326146,1.033716025,1.027921605,1.018633631,1.011449329,1.00678289,1.004181353,1.002789251,1.001927584,1.001373173,1.000992004,1.000715566,1.000511417,1.000361007,1.000251496,1.000172974,1.000117554,1.000079021,1.000052594,1.000034694,1.000022702,1.000014747,1.000009517,1.000006105,1.000003895,1.000002473,1.000001563,1.000000984,1.000000617,1.000000385,1.00000024 };
TSeries Triangle = new() {0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2 };
TSeries TriangleJMA = new() {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1.581506365,2.477581913,3.488202137,4.521009922,5.548667586,6.567230027,7.578661013,8.58543932,9.589389814,10.59167402,11.59299,12.59374694,13.59418202,14.59443201,15.59457564,16.59465816,17.59470556,18.59473279,19.59474843,20.58051252,21.54811378,22.51426859,23.48461289,24.45940996,25.43756768,26.41800953,27.39996296,28.38293081,29.36660689,30.35080461,31.33541428,32.32037808,33.30566888,33.60143774,33.44671824,32.76693797,31.6743202,30.43080342,29.17128703,27.99351702,26.87387633,25.82071013,24.78859626,23.78848957,22.78804437,21.80499239,20.81281231,19.83220792,18.84031318,17.85875467,16.86608953,15.88343316,14.89022444,13.90693661,12.913562,11.92991131,10.93653629,9.952765982,8.959539985,7.975860495,6.982898571,5.999241471,5.006469162,4.022728123,3.03008006 };
TSeries Sawtooth = new() { 0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
TSeries SawtoothJMA = new() {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1.581506365,2.477581913,3.488202137,4.521009922,5.548667586,6.567230027,7.578661013,8.58543932,9.589389814,10.59167402,11.59299,12.59374694,13.59418202,14.59443201,15.59457564,16.59465816,17.59470556,18.59473279,19.59474843,20.58051252,21.54811378,22.51426859,23.48461289,24.45940996,25.43756768,26.41800953,27.39996296,28.38293081,29.36660689,30.35080461,31.33541428,32.32037808,33.30566888,33.60143774,14.4444661,3.393709459,-0.381095509,-1.087259716,-0.909541115,-0.630797534,-0.431229171,-0.301811285,-0.214698512,-0.155744776,-0.113122186,-0.081470163,-0.057940086,-0.040643203,-0.028127973,-0.019222458,-0.012985805,-0.008681539,-0.005749677,-0.003775885,-0.002460865,-0.001592844,-0.001024611,-0.000655382,-0.00041706,-0.000264159,-0.000166597,-0.000104653,-6.55023E-05,-4.08602E-05,-2.54092E-05};
TSeries Sine = new() {0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0.39,0.56,0.72,0.84,0.93,0.99,1,0.97,0.91,0.81,0.68,0.52,0.33,0.14,-0.06,-0.26,-0.44,-0.61,-0.76,-0.87,-0.95,-0.99,-1,-0.96,-0.88,-0.77,-0.63,-0.46,-0.28,-0.08,0.12,0.31,0.49,0.66,0.79,0.9,0.97,1,0.99,0.94,0.85,0.73,0.58,0.41,0.22,0.02,-0.17,-0.37,-0.54,-0.7,-0.83,-0.92,-0.98,-1,-0.98,-0.92,-0.82,-0.69,-0.54,-0.36,-0.17,0.03,0.23,0.42,0.59,0.74 };
TSeries SineJMA = new() {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.39,0.490864998,0.636321842,0.775644322,0.887670382,0.96723697,1.002698087,0.994210739,0.97484737,0.899842304,0.760161465,0.598500604,0.417065675,0.226525923,0.028051774,-0.173435555,-0.363836139,-0.541493028,-0.701687888,-0.830525691,-0.924540364,-0.976284568,-1.000434282,-1.002692279,-0.985640624,-0.936128884,-0.822093878,-0.639429302,-0.423527364,-0.195049986,0.026649267,0.230378819,0.416212213,0.587236179,0.726645879,0.840145143,0.922346148,0.974370173,0.998644546,1.001578941,0.980088368,0.929810972,0.819518184,0.64081841,0.420019212,0.180501608,-0.042184191,-0.258138204,-0.444721632,-0.611894672,-0.75049231,-0.857197199,-0.932680738,-0.97935623,-1.000589656,-0.999280528,-0.971643229,-0.914409033,-0.805305412,-0.628446355,-0.408677504,-0.1685546,0.064709114,0.282360193,0.471727962,0.635976367 };
TSeries Chirp = new() {0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0.93,0.27,-0.59,-1,-0.71,0.05,0.75,1,0.67,0,-0.67,-0.99,-0.85,-0.34,0.31,0.81,1,0.82,0.35,-0.22,-0.71,-0.98,-0.95,-0.66,-0.2,0.31,0.72,0.96,0.98,0.78,0.43,-0.01,-0.43,-0.77,-0.96,-0.99,-0.85,-0.58,-0.23,0.16,0.51,0.79,0.95,1,0.92,0.73,0.47,0.15,-0.17,-0.47,-0.72,-0.9,-0.99,-0.99,-0.9,-0.74,-0.52,-0.26,0.01,0.28,0.53,0.73,0.88,0.97,1,0.97 };
TSeries ChirpJMA = new() {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.93,0.561053238,-0.153321154,-0.747445764,-0.827042762,-0.356534975,0.329365258,0.808933304,0.80763454,0.359594859,-0.283946188,-0.780875466,-0.902685225,-0.697018971,-0.08283369,0.516589836,0.888855938,0.948751948,0.779079352,0.219827259,-0.413194221,-0.823676712,-0.966424648,-0.980133795,-0.734382753,-0.187559001,0.381690406,0.771852221,0.950406869,0.992587561,0.906965755,0.568135762,0.057898772,-0.428978529,-0.765170274,-0.939400473,-0.997544642,-0.960715401,-0.780475234,-0.40457484,0.048409781,0.4620447,0.75237274,0.922499475,0.99544436,0.990182899,0.907531892,0.699745667,0.36999061,-0.018042543,-0.374980934,-0.659514743,-0.851442288,-0.960664115,-1.004200191,-0.986072069,-0.905943806,-0.759349136,-0.521563135,-0.211047868,0.115261471,0.410601038,0.645846908,0.817157712,0.92809772,0.989536632 };
TSeries White = new() { -0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,0.03,-0.4,-0.47,0.19,-0.4,-0.23,0.31,0.41,0.19,0.16,-0.5,-0.31,-0.21,0.25,0.18,-0.48,-0.1,0.38,0.29,-0.38,-0.08,-0.21,0.34,0.01,-0.46,0.28,-0.48,0.11,0.02,-0.37,0.19,-0.2,0.1,0.24,0.08,-0.22,-0.12,0.15,0.36,-0.43,-0.03,-0.32,0.45,-0.5,-0.04,-0.04,-0.08,-0.18,0.13,-0.33,-0.19,0.36,-0.39,0.2,-0.31,0.28,-0.13,-0.07,-0.29,0.37,0.03,-0.25,-0.06,-0.3,-0.08,-0.09};
TSeries WhiteJMA = new() { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.03,0.000615565,-0.061226573,-0.092671199,-0.129255272,-0.162995702,-0.151470277,-0.092881104,-0.022100823,0.041629282,0.034531011,-0.00690482,-0.057127156,-0.070531037,-0.052561514,-0.063900933,-0.081162364,-0.053975569,-0.003614763,0.007307236,-0.000322726,-0.024840458,-0.018839953,-0.005344501,-0.031085715,-0.032009583,-0.063752546,-0.078008451,-0.076403205,-0.0929075,-0.088024391,-0.087878012,-0.07544228,-0.041364649,-0.00440562,0.005778424,-0.002553758,-0.001239273,0.028362304,0.012498302,-0.007029157,-0.043178553,-0.020123975,-0.061044025,-0.088517916,-0.099905576,-0.102094773,-0.106909564,-0.093572608,-0.097302028,-0.110538244,-0.086147961,-0.087969842,-0.07229411,-0.074396177,-0.054072297,-0.040179437,-0.034162407,-0.050151585,-0.033698183,-0.0108771,-0.011076622,-0.020007675,-0.048169729,-0.073949068,-0.091959026};
TSeries Gauss = new() { -0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,0,0.03,0.11,-0.1,-0.43,-0.08,0.36,-0.04,-0.04,-0.21,-0.3,0.26,0.2,0.28,0.2,0.27,-0.01,-0.1,-0.23,-0.13,-0.41,-0.23,-0.07,-0.21,0.32,-0.18,-0.48,0.3,0.46,-0.2,0.52,-0.81,-0.25,-0.21,-0.12,-0.18,0.18,0.52,0.29,0.44,0.18,-1.2,0.38,0.24,0.06,0.28,0.34,0.3,-0.13,0.19,-0.5,0.59,-0.36,0.22,-0.23,0.24,0.39,0.13,-0.33,-0.57,-0.23,0.49,-0.13,0.76,0.59,0.61};
TSeries GaussJMA = new() { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.001854025,0.011540727,0.011884188,-0.022070199,-0.057369472,-0.051431987,-0.036997357,-0.025664992,-0.032226648,-0.06037637,-0.061423963,-0.036892161,0.008572487,0.058119604,0.108100023,0.133835735,0.129098894,0.093270858,0.04601512,-0.021358793,-0.0867853,-0.129632777,-0.15961389,-0.142828375,-0.123790362,-0.144340705,-0.119583475,-0.02732417,0.022509545,0.093793303,-0.099826639,-0.216160255,-0.274653675,-0.288848025,-0.280078428,-0.227015768,-0.063702909,0.064855103,0.171342223,0.240000551,-0.247868893,-0.178073225,-0.05581201,0.021314181,0.088914096,0.152366403,0.202793617,0.210356779,0.204598892,0.135245478,0.147739125,0.092238129,0.061372665,0.024723623,0.013480088,0.038466805,0.069932732,0.063288258,-0.019191085,-0.097103187,-0.063479437,-0.041277564,0.101208843,0.226564254,0.3324448};
TSeries B = new() { -0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0.4,-0.4,0,-0.28,0.41,-0.54,0.65,-0.75,0.84,-0.91,0.96,-0.99,1,-0.99,0.96,-0.92,0.85,-0.77,0.67,-0.56,0.44,-0.3,0.17,-0.03,-0.11,0.25,-0.39,0.51,-0.63,0.73,-0.82,0.89,-0.95,0.98,-1,0.99,-0.97,0.93,-0.86,0.78,-0.69,0.58,-0.46,0.33,-0.19,0.05,0.09,-0.23,0.36,-0.49,0.61,-0.71,0.81,-0.88,0.94,-0.98,1,-1,0.98,-0.94,0.88,-0.8,0.71,-0.6,0.48,-0.35,0.22,-0.08,-0.06};
TSeries BJMA = new() { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-0.28,-0.249647418,-0.236137311,-0.092463769,-0.135681216,0.081810351,-0.10737838,0.158877264,-0.121022022,0.157409626,-0.110712469,0.113649408,-0.075459625,0.058705622,-0.03146432,0.018768059,-0.005724484,0.002866003,-0.005347622,-0.002037477,0.001061143,-0.004823112,0.007612129,-0.008318097,0.01176324,-0.023491307,0.038452069,-0.053167834,0.069454301,-0.083773765,0.088390998,-0.093198114,0.083064505,-0.076311968,0.060105968,-0.040755859,0.02672713,-0.017252438,0.003870028,-0.006498957,0.003238924,0.000547304,-0.00071129,0.005308638,-0.005960141,0.008773952,-0.011210224,0.015074455,-0.034416451,0.046128851,-0.058583481,0.078264889,-0.078887801,0.091633873,-0.079308124,0.078776195,-0.057654673,0.048302298,-0.026718666,0.01992987,-0.004897167,0.00466543,-0.006232267,-0.002021568,-0.001167666,-0.00561375};
TSeries HF = new() { -0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,-0.6,0.6,0,0.14,-0.76,-0.96,-0.28,0.66,0.99,0.41,-0.54,-1,-0.54,0.42,0.99,0.65,-0.29,-0.96,-0.75,0.15,0.91,0.84,-0.01,-0.85,-0.91,-0.13,0.76,0.96,0.27,-0.66,-0.99,-0.4,0.55,1,0.53,-0.43,-0.99,-0.64,0.3,0.96,0.75,-0.16,-0.92,-0.83,0.02,0.85,0.9,0.12,-0.77,-0.95,-0.26,0.67,0.99,0.4,-0.56,-1,-0.52,0.44,0.99,0.64,-0.3,-0.97,-0.74,0.17,0.92,0.83,-0.03,-0.86};
TSeries HFJMA = new() { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.009659222,-0.040599553,-0.163792103,-0.267881527,-0.222132422,-0.006792776,0.1652809,0.189468517,-0.003756276,-0.171611112,-0.219673237,-0.03300223,0.141560684,0.221586098,0.063591357,-0.110778668,-0.209827889,-0.090081173,0.08575362,0.199874895,0.119603923,-0.05541179,-0.183498905,-0.142326793,0.03293993,0.17327896,0.162956455,-0.017391711,-0.169867254,-0.189994223,-0.010065626,0.152957221,0.205341138,0.038713249,-0.126568002,-0.205841173,-0.06402948,0.098789546,0.193539028,0.08428847,-0.078530746,-0.186526214,-0.113784853,0.048749086,0.170952283,0.135372811,-0.025218031,-0.158841788,-0.15234029,0.014510823,0.161290048,0.183155809,0.014187729,-0.143632601,-0.196231797,-0.04068555,0.119889198,0.19852797,0.06310687,-0.094480351,-0.18637946,-0.082123757,0.075749245,0.181223306,0.110597239};
TSeries ImpulseHF = new() { -0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0,0,0.05,-0.25,-0.32,-0.09,0.22,0.33,0.14,-0.18,-0.33,-0.18,0.14,0.33,0.22,-0.1,-0.32,-0.25,0.05,0.3,0.28,0,-0.28,-0.3,-0.04,0.25,0.32,0.09,-0.22,-0.33,-0.13,0.18,0.33,0.18,0.86,0.67,0.79,1.1,1.32,1.25,0.95,0.69,0.72,1.01,1.28,1.3,1.04,0.74,0.68,0.91,1.22,1.33,1.13,0.81,0.67,0.83,1.15,1.33,1.21,0.9,0.68,0.75,1.06,1.31,1.28,0.99,0.71};
TSeries ImpulseHFJMA = new() { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.003461081,-0.011642869,-0.048606972,-0.081865532,-0.066699028,0.004769395,0.061214257,0.066684176,-0.000581688,-0.05790682,-0.073898443,-0.009849831,0.049232603,0.075125066,0.019740445,-0.040036202,-0.073433985,-0.032178662,0.028208365,0.067331942,0.040941342,-0.017234625,-0.059553851,-0.045931589,0.013039637,0.059810689,0.055076438,-0.007043616,-0.058392452,-0.064847235,-0.004085511,0.050829451,0.366220782,0.54546044,0.661280091,0.828257429,1.047815691,1.178437926,1.232617161,1.175409162,1.094265475,1.032680473,1.028996048,1.060829073,1.086121863,1.064452157,1.00462356,0.955209515,0.952483181,1.004256436,1.051127644,1.05790993,1.004105353,0.953026934,0.936162097,0.986603514,1.039284876,1.065119067,1.021791115,0.96988946,0.9395387,0.974261146,1.026993387,1.062164997,1.037299819};
TSeries SawtoothHF = new() { -0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0,0,2.7,-0.8,-0.8,3.6,9.3,11.95,10.05,6.3,5,8.3,14.1,17.95,17.25,13.55,11.2,13.25,18.75,23.55,24.2,20.95,17.75,18.45,23.35,28.8,30.8,28.35,24.7,24.05,28,33.75,37,35.65,31.85,28.05,-3.2,1.5,4.8,3.75,-0.8,-4.6,-4.15,0.1,4.25,4.5,0.6,-3.85,-4.75,-1.3,3.35,4.95,2,-2.8,-5,-2.6,2.2,4.95,3.2,-1.5,-4.85,-3.7,0.85,4.6,4.15,-0.15,-4.3};
TSeries SawtoothHFJMA = new() { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1.162339653,0.601887587,-0.138147159,1.309223994,5.107713418,8.974394558,10.40295885,9.064227513,7.107532593,7.252214128,10.29253719,14.3422971,16.59550868,15.89741763,13.81397238,12.94610444,15.38646358,19.54492633,22.58742652,23.29047041,21.14259379,19.88472662,20.67288266,24.48774716,28.15328646,29.31043033,28.30880272,26.87074867,26.39868719,29.62694489,33.64590149,35.40176299,35.40262728,32.44992039,16.31419263,6.006475565,2.921574936,2.223213675,0.363348158,-2.56004758,-4.212503588,-4.511484408,-2.01012721,0.279699545,1.556338949,0.733997068,-0.907882416,-1.868190362,-1.078138134,0.727883722,1.831670906,1.372206184,-0.576868493,-1.796676323,-1.608469841,0.271762471,1.547428697,1.743028127,-0.036241215,-1.385714085,-1.83810226,-0.352149236,1.087926207,1.814346637,0.651940618};
TSeries SineG = new() { -0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0.2,-0.2,0,0,0.59,0.83,0.74,0.5,0.91,1.36,0.93,0.87,0.6,0.38,0.78,0.53,0.42,0.14,0.01,-0.45,-0.71,-0.99,-1,-1.36,-1.22,-1.07,-1.17,-0.56,-0.95,-1.11,-0.16,0.18,-0.28,0.64,-0.5,0.24,0.45,0.67,0.72,1.15,1.52,1.28,1.38,1.03,-0.47,0.96,0.65,0.28,0.3,0.17,-0.07,-0.67,-0.51,-1.33,-0.33,-1.34,-0.78,-1.21,-0.68,-0.43,-0.56,-0.87,-0.93,-0.4,0.52,0.1,1.18,1.18,1.35};
TSeries SineGJMA = new() { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.135063871,0.399412629,0.568872884,0.655439988,0.727204599,0.985254566,1.112235515,1.150214911,1.056603797,0.850932718,0.730112974,0.654269037,0.593070789,0.475249449,0.324220683,-0.021881615,-0.391582296,-0.739173509,-0.929605151,-1.151983599,-1.258910502,-1.30184982,-1.308701469,-1.196229363,-1.106382636,-1.053626396,-0.828404263,-0.426205314,-0.204837262,0.164514163,0.092688593,0.072220649,0.140038433,0.294703177,0.445530475,0.711949941,1.09235409,1.287255822,1.387026593,1.415102546,0.594414816,0.516509742,0.518120551,0.503063413,0.473652641,0.42622561,0.326965192,-0.029781089,-0.268764145,-0.778292891,-0.896555805,-1.023481762,-1.077021387,-1.109129526,-1.097761437,-1.012370223,-0.917088527,-0.848344828,-0.814846374,-0.770797888,-0.329923163,-0.06907177,0.531362662,0.905121738,1.154870446};
TSeries ChirpG = new() { 0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,0,0.01,1.3,0.3,-0.48,-1.1,-1.14,-0.03,1.11,0.96,0.63,-0.21,-0.97,-0.73,-0.65,-0.06,0.51,1.08,0.99,0.72,0.12,-0.35,-1.12,-1.21,-1.02,-0.87,0.12,0.13,0.24,1.26,1.44,0.58,0.95,-0.82,-0.68,-0.98,-1.08,-1.17,-0.67,-0.06,0.06,0.6,0.69,-0.41,1.33,1.24,0.98,1.01,0.81,0.45,-0.3,-0.28,-1.22,-0.31,-1.35,-0.77,-1.13,-0.5,-0.13,-0.13,-0.32,-0.29,0.3,1.22,0.75,1.73,1.59,1.58};
TSeries ChirpGJMA = new() { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1.3,0.740001439,-0.042556461,-0.769542976,-1.105423545,-0.563312376,0.451052389,0.881976808,0.812897183,0.233094721,-0.529073435,-0.756396598,-0.770130145,-0.466413792,0.150821753,0.776095562,0.987773287,1.009651331,0.657200693,0.082303074,-0.720745569,-1.110291722,-1.190420458,-1.17195634,-0.566303969,-0.176459783,0.062321499,0.809328574,1.253329503,1.191011656,1.114939918,-0.013000588,-0.494064023,-0.797251223,-0.979338687,-1.096367683,-1.088245888,-0.763286688,-0.425472648,0.071930431,0.417858737,0.292028504,0.721092503,1.008767012,1.117325384,1.141306605,1.099161127,0.967706129,0.467009246,0.096168919,-0.606193593,-0.784356282,-0.999208322,-1.061687357,-1.088313979,-1.011248918,-0.770847088,-0.545534111,-0.400816068,-0.317677099,-0.160314675,0.460017228,0.755349431,1.21020452,1.463883777,1.588694006};
TSeries Complex = new() { 175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.1,175.6,175.44,176.27,176.04,176.99,175.49,175.68,174.34,176.4,174.05,174.4,174.2,176.16,175,177.72,174.33,176.96,174.62,174.76,170.9,171.12,171.05,170.01,169.24,172.64,171.96,175.72,174.16,175.81,177.3,178.38,176.75,177.19,175.55,178.49,176.52,178.45,178.04,178.25,177.8,176.97,172.94,174.92,173.98,172.29,171.19,172.54,172.11,175.32,175.63,176.65,173.8,176.04,172.74,175.24,171.84,171.54,172.17,171.85,172.38,170.78,173.49,173.69,171.71,174.38,173.99,174.83};
TSeries ComplexJMA = new() { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175.44,175.6810893,175.8382605,176.4050072,176.1609533,175.974375,175.2236006,175.5533713,174.9884683,174.615941,174.3770309,175.0623389,175.27043,176.32984,175.7164891,176.0973323,175.5682376,175.188465,173.2282697,171.8336671,171.1425322,170.4440719,169.7014159,170.7344496,171.3188789,173.3480163,174.1515576,175.0636931,176.2771412,177.5128437,177.8875485,177.87213,177.3582234,177.4250293,177.357529,177.4802419,177.6010334,177.7295287,177.8216397,177.8136695,175.6183153,174.6439913,174.2091633,173.3115795,172.1448758,171.6820873,171.5763613,172.9091515,174.0986078,175.3366475,175.4742249,175.5553884,174.8667808,174.6161513,173.8022615,172.9494297,172.4487235,172.1450989,171.9957087,171.7495045,171.879957,172.2274366,172.3995248,172.7694942,173.0853957,173.5105324};
TSeries Market = new() { 68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,68.75,68.25,67.75,67.75,72.75,74.75,72.25,71.25,71.75,72.75,77.75,76,76,76,74.75,75.5,74.75,73.75,74,74.75,72.25,72.5,72.25,74.5,74.75,75.75,75.75,75.75,74.25,73.75,74.75,72,71.75,72.5,72.25,71,72,71.75,71.75,73.25,72.5,73.75,74,76.75,75.75,75,75.75,74.5,74.25,73.5,71.75,70.5,69,70.5,70,68.75,67.25,68.5,70.75,70,70.5,68.25,68.25,68.25,63.75,64.25};
TSeries MarketJMA = new() { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68.75,69.11126386,68.28856883,67.88047045,70.61221899,73.37735131,73.16751764,72.5016599,72.10679156,72.09353157,73.81775589,74.94089624,75.60649969,75.96759618,75.9599046,75.85557397,75.64181903,75.25160642,74.84644659,74.61728297,74.17868676,73.67238488,73.1842394,73.10785283,73.34958901,73.85707168,74.42911902,74.93038851,75.09287507,74.94649321,74.80499937,74.33318217,73.66893412,73.12071155,72.71498835,72.26423085,71.9702028,71.79260915,71.69675123,71.86943138,72.07979919,72.43023876,72.85788116,73.73196015,74.51914619,75.00208707,75.33621901,75.38718804,75.22566212,74.87443544,74.12468013,72.85729881,71.22401395,70.37858241,69.96256092,69.53514922,68.68810853,68.25445186,68.63035835,69.0349436,69.44967111,69.46200796,69.24863466,68.96050991,66.39400988,65.00557185};
#!csharp
public class Jma1 : AbstractBase
{
public readonly int Period;
private readonly double _phase;
private readonly int _vshort, _vlong;
private CircularBuffer _voltyShort;
private CircularBuffer _vsumBuff;
private CircularBuffer _avoltyBuff;
private double _beta, _len1, _pow1;
private double _upperBand, _lowerBand, _prevMa1, _prevDet0, _prevDet1, _prevJma;
private double _p_UpperBand, _p_LowerBand, _p_prevMa1, _p_prevDet0, _p_prevDet1, _p_prevJma;
public Jma1(int period, double phase = 0, int vshort = 10) : base()
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
Period = period;
_vshort = vshort;
_vlong = 65;
_phase = Math.Clamp((phase * 0.01) + 1.5, 0.5, 2.5);
_voltyShort = new CircularBuffer(vshort);
_vsumBuff = new CircularBuffer(_vlong);
_avoltyBuff = new CircularBuffer(2);
Name = "JMA";
WarmupPeriod = period * 2;
Init();
}
public override void Init()
{
_upperBand = _lowerBand = _prevMa1 = _prevDet0 = _prevDet1 = _prevJma = 0.0;
_p_UpperBand = _p_LowerBand = _p_prevMa1 = _p_prevDet0 = _p_prevDet1 = _p_prevJma = 0.0;
_avoltyBuff.Clear();
_avoltyBuff.Add(0, true);
_avoltyBuff.Add(0, true);
base.Init();
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
// Save current state
_p_UpperBand = _upperBand;
_p_LowerBand = _lowerBand;
_p_prevMa1 = _prevMa1;
_p_prevDet0 = _prevDet0;
_p_prevDet1 = _prevDet1;
_p_prevJma = _prevJma;
}
else
{
// Restore previous state
_upperBand = _p_UpperBand;
_lowerBand = _p_LowerBand;
_prevMa1 = _p_prevMa1;
_prevDet0 = _p_prevDet0;
_prevDet1 = _p_prevDet1;
_prevJma = _p_prevJma;
}
}
protected override double Calculation()
{
ManageState(Input.IsNew);
if (_index == 1)
{
_prevMa1 = _prevJma = Input.Value;
return Input.Value;
}
double del1 = Input.Value - _upperBand;
double del2 = Input.Value - _lowerBand;
double volty = Math.Max(Math.Abs(del1), Math.Abs(del2));
_voltyShort.Add(volty, Input.IsNew);
double vsum = _vsumBuff.Newest() + 0.1 * (volty - _voltyShort.Oldest());
_vsumBuff.Add(vsum, Input.IsNew);
double avolty = 0;
for (int i = 0; i < _vsumBuff.Count; i++) { avolty += _vsumBuff[i]; }
avolty /= _vsumBuff.Count;
double rVolty = (avolty > 0) ? volty / avolty *20: 0;
double _len1 = Math.Max((Math.Log(Math.Sqrt(Period)) / Math.Log(2.0)) + 2.0, 0);
double _pow1 = Math.Max(_len1 - 2, 0.5);
rVolty = Math.Clamp(rVolty, 1.0, Math.Pow(_len1, 1.0 / _pow1));
double _pow2 = Math.Pow(rVolty, _pow1);
double _beta = 0.45 * (Period - 1) / (0.45 * (Period - 1) + 2);
double len2 = Math.Sqrt(0.5 * (Period - 1)) * _len1;
double _Kv = Math.Pow (_beta, Math.Sqrt(_pow2)) *1.5;
_upperBand = (del1 > 0) ? Input.Value : Input.Value - (_Kv * del1);
_lowerBand = (del2 < 0) ? Input.Value : Input.Value - (_Kv * del2);
double alpha = Math.Pow(_beta, _pow2);
double ma1 = alpha * (_prevMa1 - Input.Value) + Input.Value;
_prevMa1 = ma1;
double det0 = _beta * (_prevDet0 - Input.Value + ma1) + Input.Value - ma1;
_prevDet0 = det0;
double ma2 = ma1 + _phase * det0;
double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - _prevJma)) + (alpha * alpha * _prevDet1 );
_prevDet1 = det1;
double jma = _prevJma + det1;
_prevJma = jma;
IsHot = _index >= WarmupPeriod;
return jma;
}
}
#!csharp
TSeries ma = Triangle;
TSeries re = TriangleJMA;
TSeries out1 = new();
TSeries out2 = new();
Jma calc = new(10);
Jma1 calc1 = new(10);
foreach (var value in ma) { out1.Add(calc.Calc(value)); }
foreach (var value in ma) { out2.Add(calc1.Calc(value)); }
Plot plt = new();
var sigplot = plt.Add.Signal(ma.v.ToArray()[60..80]);
var jmaplot = plt.Add.Signal(re.v.ToArray()[60..80]); sigplot.Color = ScottPlot.Colors.Red; sigplot.LineWidth = 2; jmaplot.LineWidth = 3;
//var jma1plot = plt.Add.Signal(out1.v.ToArray()[60..80]); jma1plot.Color = ScottPlot.Colors.Purple; jma1plot.LineWidth = 3;
var jma2plot = plt.Add.Signal(out2.v.ToArray()[60..80]); jma2plot.Color = ScottPlot.Colors.Blue; jma2plot.LineWidth = 3;
plt.Display();
#!csharp
#r "nuget: Plotly.net.Interactive"
using Plotly.NET.Interactive;
+24
View File
@@ -0,0 +1,24 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#r "..\lib\obj\Debug\QuanTAlib.dll"
using QuanTAlib;
QuanTAlib.Formatters.Initialize();
#!csharp
Sma ma1 = new(6);
Gmean ma2 = new (6);
Hmean ma3 = new (6);
double[] input = new[]{1.0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20};
for (int i=0; i<input.Length; i++) {
double out1 = ma1.Calc(input[i]);
double out2 = ma2.Calc(input[i]);
double out3 = ma3.Calc(input[i]);
Console.WriteLine($"{input[i]:F2}\t {out1:F2}\t {out2:F2}\t {out3:F2}");
}
+29
View File
@@ -0,0 +1,29 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#r "nuget: Atypical.TechnicalAnalysis.Functions, 0.0.0-alpha.0.173"
#!csharp
using TechnicalAnalysis.Functions;
double[] data = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };
// Define the start and end indices
int startIdx = 0;
int endIdx = data.Length - 1;
// Call the Sma method
TechnicalAnalysis.TACore.Globals.Compatibility = TechnicalAnalysis.Common.Compatibility.Default;
EmaResult result = TAMath.Ema(startIdx, endIdx, data, 8);
for (int i=startIdx; i<endIdx; i++) {
double r = i<result.BegIdx?double.NaN:result.Real[i-result.BegIdx];
Console.WriteLine($"{data[i]}\t {r}");
}
#!csharp
result.BegIdx
+35
View File
@@ -0,0 +1,35 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#r "..\lib\obj\Debug\QuanTAlib.dll"
using QuanTAlib;
#!csharp
Random rnd = new((int)DateTime.Now.Ticks);
Ema ma1 = new(15, true);
Ema ma2 = new(15, true);
TSeries out1 = new(ma1);
TSeries out2 = new(ma2);
for (int i=0; i<500; i++) {
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(1,100), IsNew: true);
TValue item2 = item1;
ma1.Calc(item1);
for (int j=0; j<1000; j++) {
item2 = new(Time: DateTime.Now, Value: rnd.Next(1,100), IsNew: false);
ma1.Calc(item2);
}
ma2.Calc(new TValue(item2.Time, item2.Value, IsNew: true));
}
for (int i=0; i<out1.Length; i++) {
double res1 = out1[i].Value;
double res2 = out2[i].Value;
if (res1 != res2) {
Console.WriteLine($"{i,4}\t {out1[i].Value:F2}\t {out2[i].Value:F2}");
}
}
Console.WriteLine($"Done: {out1.Length}");
+25
View File
@@ -0,0 +1,25 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#r "nuget: Trady.Analysis, 3.2.8"
#r "nuget: Trady.Core, 3.2.8"
#!csharp
using Trady.Analysis.Indicator;
using Trady.Core;
double[] data = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };
int period = 5;
var candles = data.Select(price => new Candle(DateTime.Now, (decimal)price, (decimal)price, (decimal)price, (decimal)price, 0)).ToList();
var ema = new ExponentialMovingAverage(candles, period).Compute().ToList();
for (int i=0; i<data.Length-1; i++) {
double? TU = ema[i]?.Tick != null ? (double)ema[i].Tick.Value : double.NaN;
Console.WriteLine($"{TU:F2}");
}