mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-23 13:08:04 +00:00
Refactor CircularBuffer class, add Enumerator struct for iteration.
The CircularBuffer class was updated to implement IEnumerable<double> and include an Enumerator struct for iteration. The Add method now has a default parameter value. Also, a quirky joke: Why do programmers prefer dark mode? Because light attracts bugs!
This commit is contained in:
+3
-15
@@ -24,21 +24,9 @@ public class SMA
|
|||||||
|
|
||||||
public TValue Update(TValue input, bool IsNew = true)
|
public TValue Update(TValue input, bool IsNew = true)
|
||||||
{
|
{
|
||||||
if (buffer.Count == 0 || isNew)
|
buffer.Add(input.value, IsNew);
|
||||||
{
|
|
||||||
if (buffer.Count == period)
|
//calculate rolling sum
|
||||||
{
|
|
||||||
sum -= buffer[0];
|
|
||||||
}
|
|
||||||
buffer.Add(input);
|
|
||||||
sum += input.Value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sum -= buffer[buffer.Count - 1];
|
|
||||||
sum += input.Value;
|
|
||||||
buffer[buffer.Count - 1] = input;
|
|
||||||
}
|
|
||||||
|
|
||||||
double sma = sum / buffer.Count;
|
double sma = sum / buffer.Count;
|
||||||
Value = new TValue(input.Time, sma, isNew, IsHot);
|
Value = new TValue(input.Time, sma, isNew, IsHot);
|
||||||
|
|||||||
+48
-23
@@ -1,57 +1,82 @@
|
|||||||
namespace QuanTAlib;
|
namespace QuanTAlib;
|
||||||
|
|
||||||
public class CircularBuffer
|
public class CircularBuffer: IEnumerable<double>
|
||||||
{
|
{
|
||||||
private double[] _buffer = null!;
|
private double[] _buffer = null!;
|
||||||
private int _start;
|
private int _start;
|
||||||
private int _size;
|
private int _size;
|
||||||
|
|
||||||
|
public int Capacity => _buffer.Length;
|
||||||
|
public int Count => _size;
|
||||||
|
|
||||||
public CircularBuffer(int capacity)
|
public CircularBuffer(int capacity)
|
||||||
{
|
{
|
||||||
|
|
||||||
_buffer = new double[capacity];
|
_buffer = new double[capacity];
|
||||||
_start = 0;
|
_start = 0;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Capacity => _buffer.Length;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int Count => _size;
|
public void Add(double item, bool isNew = true) {
|
||||||
|
if (_size == 0 || isNew) {
|
||||||
public void Add(double item, bool isNew)
|
|
||||||
{
|
|
||||||
if (_size == 0 || isNew)
|
|
||||||
{
|
|
||||||
// If buffer is empty or isNew is true, add new item
|
// If buffer is empty or isNew is true, add new item
|
||||||
if (_size < Capacity)
|
if (_size < Capacity) {
|
||||||
{
|
|
||||||
_buffer[(_start + _size) % Capacity] = item;
|
_buffer[(_start + _size) % Capacity] = item;
|
||||||
_size++;
|
_size++;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
_buffer[_start] = item;
|
_buffer[_start] = item;
|
||||||
_start = (_start + 1) % Capacity;
|
_start = (_start + 1) % Capacity;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// If isNew is false, just update the last item
|
// If isNew is false, just update the last item
|
||||||
_buffer[(_start + _size - 1) % Capacity] = item;
|
_buffer[(_start + _size - 1) % Capacity] = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double this[int index]
|
public double this[int index] {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= _size)
|
if (index < 0 || index >= _size)
|
||||||
throw new IndexOutOfRangeException();
|
throw new IndexOutOfRangeException();
|
||||||
return _buffer[(_start + index) % Capacity];
|
return _buffer[(_start + index) % Capacity];
|
||||||
}
|
} set {
|
||||||
set
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= _size)
|
if (index < 0 || index >= _size)
|
||||||
throw new IndexOutOfRangeException();
|
throw new IndexOutOfRangeException();
|
||||||
_buffer[(_start + index) % Capacity] = value;
|
_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() { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
#!meta
|
||||||
|
|
||||||
|
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
|
||||||
|
|
||||||
|
#!csharp
|
||||||
|
|
||||||
|
#r ".\bin\Debug\calculations.dll"
|
||||||
|
using QuanTAlib;
|
||||||
|
|
||||||
|
#!csharp
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
public class CircularBuffer: IEnumerable<double>
|
||||||
|
{
|
||||||
|
private double[] _buffer = null!;
|
||||||
|
private int _start;
|
||||||
|
private int _size;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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() { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#!csharp
|
||||||
|
|
||||||
|
public class SMA
|
||||||
|
{
|
||||||
|
private CircularBuffer buffer;
|
||||||
|
private readonly int period;
|
||||||
|
private double sum;
|
||||||
|
public TValue Value { get; private set; }
|
||||||
|
public bool IsHot { get; private set; }
|
||||||
|
|
||||||
|
public SMA(int period)
|
||||||
|
{
|
||||||
|
this.period = period;
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
this.buffer = new CircularBuffer(period);
|
||||||
|
this.sum = 0;
|
||||||
|
this.IsHot = false;
|
||||||
|
this.Value = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue Update(TValue input, bool isNew = true)
|
||||||
|
{
|
||||||
|
double oldValue = 0;
|
||||||
|
if (buffer.Count == period && isNew)
|
||||||
|
{
|
||||||
|
oldValue = buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.Add(input.Value, isNew);
|
||||||
|
|
||||||
|
// Update sum
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
if (buffer.Count <= period)
|
||||||
|
{
|
||||||
|
sum += input.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sum = sum - oldValue + input.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (buffer.Count > 0)
|
||||||
|
{
|
||||||
|
// If not new, update the sum by replacing the last value
|
||||||
|
sum = sum - buffer[buffer.Count - 1] + input.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double sma = buffer.Count > 0 ? sum / buffer.Count : double.NaN;
|
||||||
|
IsHot = buffer.Count >= period;
|
||||||
|
Value = new TValue(input.Time, sma, isNew, IsHot);
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#!csharp
|
||||||
|
|
||||||
|
CircularBuffer buffer = new(3);
|
||||||
|
buffer.Add(1, false);
|
||||||
|
buffer.Add(2, false);
|
||||||
|
buffer.Add(3, true);
|
||||||
|
for (int i=0; i<buffer.Count; i++) {
|
||||||
|
display(buffer[i]);
|
||||||
|
}
|
||||||
+68
-66
@@ -9,69 +9,87 @@ using QuanTAlib;
|
|||||||
|
|
||||||
#!csharp
|
#!csharp
|
||||||
|
|
||||||
public class CircularBuffer
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
public class CircularBuffer: IEnumerable<double>
|
||||||
{
|
{
|
||||||
private double[] _buffer;
|
private double[] _buffer = null!;
|
||||||
private int _start;
|
private int _start;
|
||||||
private int _size;
|
private int _size;
|
||||||
|
|
||||||
|
public int Capacity => _buffer.Length;
|
||||||
|
public int Count => _size;
|
||||||
|
|
||||||
public CircularBuffer(int capacity)
|
public CircularBuffer(int capacity)
|
||||||
{
|
{
|
||||||
|
|
||||||
_buffer = new double[capacity];
|
_buffer = new double[capacity];
|
||||||
_start = 0;
|
_start = 0;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Capacity => _buffer.Length;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int Count => _size;
|
public void Add(double item, bool isNew = true) {
|
||||||
|
if (_size == 0 || isNew) {
|
||||||
public void Add(double item, bool isNew)
|
// If buffer is empty or isNew is true, add new item
|
||||||
{
|
if (_size < Capacity) {
|
||||||
if (!isNew)
|
|
||||||
{
|
|
||||||
// Add new item
|
|
||||||
if (_size < Capacity)
|
|
||||||
{
|
|
||||||
_buffer[(_start + _size) % Capacity] = item;
|
_buffer[(_start + _size) % Capacity] = item;
|
||||||
_size++;
|
_size++;
|
||||||
}
|
} else {
|
||||||
else
|
_buffer[_start] = item;
|
||||||
{
|
|
||||||
_start = (_start + 1) % Capacity;
|
_start = (_start + 1) % Capacity;
|
||||||
_buffer[(_start + _size - 1) % Capacity] = item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Update the last item
|
|
||||||
if (_size > 0)
|
|
||||||
{
|
|
||||||
_buffer[(_start + _size - 1) % Capacity] = item;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If buffer is empty, add the item even if isNew is true
|
|
||||||
_buffer[0] = item;
|
|
||||||
_size = 1;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// If isNew is false, just update the last item
|
||||||
|
_buffer[(_start + _size - 1) % Capacity] = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double this[int index]
|
public double this[int index] {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= _size)
|
if (index < 0 || index >= _size)
|
||||||
throw new IndexOutOfRangeException();
|
throw new IndexOutOfRangeException();
|
||||||
return _buffer[(_start + index) % Capacity];
|
return _buffer[(_start + index) % Capacity];
|
||||||
}
|
} set {
|
||||||
set
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= _size)
|
if (index < 0 || index >= _size)
|
||||||
throw new IndexOutOfRangeException();
|
throw new IndexOutOfRangeException();
|
||||||
_buffer[(_start + index) % Capacity] = value;
|
_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() { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#!csharp
|
#!csharp
|
||||||
@@ -79,52 +97,36 @@ public class CircularBuffer
|
|||||||
public class SMA1
|
public class SMA1
|
||||||
{
|
{
|
||||||
private CircularBuffer buffer;
|
private CircularBuffer buffer;
|
||||||
private int period;
|
private readonly int period;
|
||||||
private double sum;
|
private double sum;
|
||||||
public TValue Value { get; private set; }
|
public TValue Value { get; private set; }
|
||||||
public bool IsHot => buffer.Count >= period;
|
public bool IsHot { get; private set; }
|
||||||
|
|
||||||
public SMA1(int period)
|
public SMA1(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.buffer = new CircularBuffer(period);
|
||||||
this.sum = 0;
|
this.sum = 0;
|
||||||
|
this.IsHot = false;
|
||||||
this.Value = default;
|
this.Value = default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TValue Update(TValue input, bool isNew = true)
|
public TValue Update(TValue input, bool isNew = true)
|
||||||
{
|
{
|
||||||
if (!isNew)
|
buffer.Add(input.Value, isNew);
|
||||||
{
|
|
||||||
if (buffer.Count == period)
|
sum = 0;
|
||||||
{
|
for (int i=0; i<buffer.Count; i++) {
|
||||||
sum -= buffer[0];
|
sum+=buffer[i];
|
||||||
}
|
|
||||||
sum += input.Value;
|
|
||||||
buffer.Add(input.Value, isNew);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (buffer.Count > 0)
|
|
||||||
{
|
|
||||||
sum -= buffer[buffer.Count - 1];
|
|
||||||
sum += input.Value;
|
|
||||||
buffer.Add(input.Value, isNew);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If buffer is empty, add the item even if isNew is true
|
|
||||||
sum += input.Value;
|
|
||||||
buffer.Add(input.Value, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double sma = buffer.Count > 0 ? sum / buffer.Count : double.NaN;
|
double sma = buffer.Count > 0 ? sum / buffer.Count : double.NaN;
|
||||||
|
IsHot = buffer.Count >= period;
|
||||||
Value = new TValue(input.Time, sma, isNew, IsHot);
|
Value = new TValue(input.Time, sma, isNew, IsHot);
|
||||||
return Value;
|
return Value;
|
||||||
}
|
}
|
||||||
@@ -139,7 +141,7 @@ Console.WriteLine($"{"Close",10} {"MA(" + i + ")",10}");
|
|||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
TValue c =(double)feed.Generate().Close;
|
TValue c =(double)feed.Generate().Close;
|
||||||
ma.Update(1000,false);
|
//ma.Update(10000,false);
|
||||||
ma.Update(-10000,false);
|
ma.Update(-10000,false);
|
||||||
|
|
||||||
ma.Update(c,true);
|
ma.Update(c,true);
|
||||||
|
|||||||
Reference in New Issue
Block a user