EMA completed

This commit is contained in:
Miha
2024-07-31 09:11:05 -04:00
parent e30701c723
commit 60c2331cc0
10 changed files with 159 additions and 175 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
#!csharp
#r "..\v2\bin\Debug\calculations.dll"
#r "\bin\Debug\calculations.dll"
using QuanTAlib;
#!csharp
+1 -1
View File
@@ -1,4 +1,4 @@
namespace QuanTAlib;
//namespace QuanTAlib;
public class GBM_Feed
{
private readonly double _mu;
+31 -28
View File
@@ -1,42 +1,45 @@
namespace QuanTAlib;
public class EMA
{
private double lastEma, lastEmaCandidate, k;
private int period, i;
private readonly int period;
private int index;
public TValue Value { get; private set; }
public bool IsHot { get; private set; }
public bool IsHot => index > period;
public int Period => Math.Min(index, period);
private double k;
private double lastEMA, lastEMAcandidate;
public EMA(int period)
{
Init(period);
public EMA(int Period) {
this.period = Period;
Init();
}
public void Init(int period)
{
this.period = period;
public void Init() {
this.Value = default;
this.index = 0;
this.k = 2.0 / (period + 1);
this.lastEma = this.lastEmaCandidate = double.NaN;
this.i = 0;
this.lastEMA = 0;
this.lastEMAcandidate = 0;
}
public TValue Update(TValue input, bool IsNew = true)
{
double ema;
if (double.IsNaN(lastEma)) { lastEma = input.Value; }
if (IsNew)
{
lastEma = lastEmaCandidate;
i++;
public TValue Update(TValue Input, bool IsNew = true) {
double ma;
if (double.IsNaN(Input.Value) || double.IsInfinity(Input.Value)) {
return new TValue(Input.Time, lastEMA, IsNew, index > period);
}
if (IsNew) {
if (index<1) { lastEMA = Input.Value; }
lastEMAcandidate = lastEMA;
index++;
} else {
if (index<=1) { lastEMAcandidate = Input.Value; }
lastEMA = lastEMAcandidate;
}
double kk = (i < period) ? (2.0 / (i + 1)) : k;
ema = lastEma + kk * (input.Value - lastEma);
lastEmaCandidate = ema;
double kk = (index <= period) ? (2.0 / (index+1)) : k;
ma = (Input.Value - lastEMA) * kk + lastEMA;
lastEMA = ma;
IsHot = i >= period;
Value = new TValue(input.Time, ema, IsNew, IsHot);
return Value;
this.Value = new TValue(Input.Time, ma, IsNew, index > period);
return this.Value;
}
}
+33 -19
View File
@@ -1,41 +1,55 @@
namespace QuanTAlib;
public class SMA
{
private CircularBuffer buffer = null!;
private int period;
private double sum;
public CircularBuffer buffer = null!;
private readonly int period;
public double sum;
public TValue Value { get; private set; }
public bool IsHot { get; private set; }
public SMA(int period)
{
Init(period);
this.period = period;
Init();
}
public void Init(int period)
public void Init()
{
this.period = period;
this.buffer = new CircularBuffer(period);
this.sum = 0;
this.IsHot = false;
this.Value = default;
}
public TValue Update(TValue input, bool IsNew = true)
public TValue Update(TValue input, bool isNew = true)
{
buffer.Add(input.value, IsNew);
//calculate rolling sum
double sma = sum / buffer.Count;
Value = new TValue(input.Time, sma, isNew, IsHot);
return Value;
if (buffer.Count == 0)
{
// If buffer is empty, always add the value regardless of isNew
buffer.Add(input.Value, true);
sum = input.Value;
}
else if (isNew && buffer.Count == buffer.Capacity)
{
// If buffer is full and it's a new value, remove oldest
sum -= buffer[0];
buffer.Add(input.Value, true);
sum += input.Value;
}
else
{
// If it's not new, or if buffer isn't full yet
if (!isNew)
{
// Remove the last value if we're updating
sum -= buffer[buffer.Count - 1];
}
buffer.Add(input.Value, isNew);
sum += input.Value;
}
double sma = buffer.Count > 0 ? sum / buffer.Count : double.NaN;
double sma = sum / buffer.Count;
IsHot = buffer.Count >= period;
Value = new TValue(input.Time, sma, IsNew, IsHot);
Value = new TValue(input.Time, sma, isNew, IsHot);
return Value;
}
}
}
+40
View File
@@ -0,0 +1,40 @@
public class Template
{
private CircularBuffer buffer = null!;
private readonly int period;
private int index;
public TValue Value { get; private set; }
public bool IsHot { get; private set; }
public Template(int Period) {
this.period = Period;
Init();
}
public void Init() {
this.buffer = new CircularBuffer(period);
this.IsHot = false;
this.Value = default;
this.index = 0;
}
public TValue Update(TValue Input, bool IsNew = true) {
this.buffer.Add(Input,IsNew);
if (this.index == 0) {
if (IsNew) { this.index++; }
this.Value = new TValue(Input.Time, Input.Value, IsNew, true);
return this.Value;
}
if (IsNew) {
// starting a new bar, fresh calc
index++;
} else {
// updating existing bar, recalc
}
double ma = Input.Value;
this.Value = new TValue(Input.Time, ma, IsNew, buffer.Count >= period);
return this.Value;
}
}
-2
View File
@@ -1,5 +1,3 @@
namespace QuanTAlib;
public class WMA
{
private CircularBuffer buffer = null!;
+10 -2
View File
@@ -1,4 +1,7 @@
namespace QuanTAlib;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
public class CircularBuffer: IEnumerable<double>
{
@@ -30,7 +33,12 @@ public class CircularBuffer: IEnumerable<double>
}
} else {
// If isNew is false, just update the last item
_buffer[(_start + _size - 1) % Capacity] = item;
if (_size > 0) {
_buffer[(_start + _size - 1) % Capacity] = item;
} else {
_buffer[_start] = item;
_size = 1;
}
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
namespace QuanTAlib;
//namespace QuanTAlib;
public readonly record struct TBar(DateTime Time, double Open, double High, double Low, double Close, double Volume, bool IsNew = true)
{
public DateTime Time { get; init; } = Time;
+1 -1
View File
@@ -1,4 +1,4 @@
namespace QuanTAlib;
//namespace QuanTAlib;
public readonly record struct TValue(DateTime Time, double Value, bool IsNew = true, bool IsHot = true)
{
+41 -120
View File
@@ -4,156 +4,77 @@
#!csharp
#r ".\bin\Debug\calculations.dll"
using QuanTAlib;
#!csharp
//#r "./bin/Debug/calculations.dll"
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
public class CircularBuffer: IEnumerable<double>
{
private double[] _buffer = null!;
private int _start;
private int _size;
#!csharp
public int Capacity => _buffer.Length;
public int Count => _size;
public CircularBuffer(int capacity)
{
_buffer = new double[capacity];
_start = 0;
_size = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(double item, bool isNew = true) {
//refine this flow
if (_size == 0 || isNew) {
// If buffer is empty or isNew is true, add new item
if (_size < Capacity) {
_buffer[(_start + _size) % Capacity] = item;
_size++;
} else {
_buffer[_start] = item;
_start = (_start + 1) % Capacity;
}
} else {
// If isNew is false, just update the last item
_buffer[(_start + _size - 1) % Capacity] = item;
}
}
public double this[int index] {
get {
if (index < 0 || index >= _size)
throw new IndexOutOfRangeException();
return _buffer[(_start + index) % Capacity];
} set {
if (index < 0 || index >= _size)
throw new IndexOutOfRangeException();
_buffer[(_start + index) % Capacity] = value;
}
}
public Enumerator GetEnumerator() => new Enumerator(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;
internal Enumerator(CircularBuffer buffer) {
_buffer = buffer;
_index = -1;
_current = default;
}
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() { }
}
}
#load "./basics/CircularBuffer.cs"
#load "./basics/TValue.cs"
#load "./basics/TBar.cs"
#load "./Indicators/SMA.cs"
#load "./Indicators/EMA.cs"
#load "./GBM_Feed.cs"
#!csharp
public class SMA1
public class Template
{
private CircularBuffer buffer;
private CircularBuffer buffer = null!;
private readonly int period;
private double sum;
private int index;
public TValue Value { get; private set; }
public bool IsHot { get; private set; }
public SMA1(int period)
{
this.period = period;
public Template(int Period) {
this.period = Period;
Init();
}
public void Init()
{
public void Init() {
this.buffer = new CircularBuffer(period);
this.sum = 0;
this.IsHot = false;
this.Value = default;
this.index = 0;
}
public TValue Update(TValue input, bool isNew = true)
{
buffer.Add(input.Value, isNew);
sum = 0;
for (int i=0; i<buffer.Count; i++) {
sum+=buffer[i];
public TValue Update(TValue Input, bool IsNew = true) {
this.buffer.Add(Input,IsNew);
//first value
if (this.index == 0) {
if (IsNew) { this.index++; }
this.Value = new TValue(Input.Time, Input.Value, IsNew, true);
return this.Value;
}
double sma = sum / buffer.Count;
IsHot = buffer.Count >= period;
Value = new TValue(input.Time, sma, isNew, IsHot);
return Value;
if (IsNew) {
// starting a new bar, fresh calc
index++;
} else {
// updating existing bar, recalc
}
double ma = Input.Value;
this.Value = new TValue(Input.Time, ma, IsNew, index > period);
return this.Value;
}
}
#!csharp
GBM_Feed feed = new(initialPrice: 100, mu: 0.1, sigma: 0.9);
int i=10;
SMA1 ma = new(i);
Console.WriteLine($"{"Close",10} {"MA(" + i + ")",10}");
for (int i = 0; i < 20; i++)
EMA ma = new(3);
Console.WriteLine($"{"Close",5} {"MA()",10}");
for (int i = 1; i < 10; i=i+1)
{
//TValue c =(double)feed.Generate().Close;
//ma.Update(10000,false);
// ma.Update(-10000,false);
//ma.Update(i,false);
//ma.Update(100,true);
ma.Update(10,true);
ma.Update(i,false);
ma.Update(i,true);
ma.Update(10000,false);
ma.Update(i+1,false);
Console.WriteLine($"{i+1} {(double)i+1,10:F2} {(double)ma.Value,10:F2}");
Console.WriteLine($"{i} {(double)ma.Value,10:F2} {ma.Value.IsNew}");
}
#!csharp