refinement

This commit is contained in:
Miha
2024-07-31 17:57:52 -07:00
parent 60c2331cc0
commit f1378e82ba
6 changed files with 382 additions and 179 deletions
+236 -35
View File
@@ -15,66 +15,267 @@ using System.Runtime.CompilerServices;
#load "./basics/CircularBuffer.cs"
#load "./basics/TValue.cs"
#load "./basics/TBar.cs"
#load "./Indicators/SMA.cs"
#load "./Indicators/EMA.cs"
//#load "./Indicators/SMA.cs"
//#load "./Indicators/EMA.cs"
#load "./GBM_Feed.cs"
#!csharp
public delegate void Signal(object source, TValue args);
#!csharp
public class Template
{
private CircularBuffer buffer = null!;
private readonly int period;
private int index;
private CircularBuffer _buffer = null!;
private readonly int _period;
private int _index, _hotIndex;
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 _sum;
private double _lastValidValue;
private double _lastAddedValue;
public Template(int Period) {
this.period = Period;
public Template(int period) {
_period = period;
Init();
}
public void Init() {
this.buffer = new CircularBuffer(period);
this.IsHot = false;
this.Value = default;
this.index = 0;
public Template(object source, int period) : this(period) {
var sourceType = source.GetType();
var updateMethod = sourceType.GetMethod("Update", new[] { typeof(TValue), typeof(bool) });
if (updateMethod != null) {
var pubEvent = sourceType.GetEvent("Pub");
if (pubEvent != null && pubEvent.EventHandlerType == typeof(Signal)) {
pubEvent.AddEventHandler(source, new Signal(Sub));
} else {
throw new ArgumentException("Source object must have a Pub event of type NewValue.");
}
} else {
throw new ArgumentException("Source object must have an Update(TValue, bool) method.");
}
}
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;
public void Init() {
_buffer = new CircularBuffer(_period);
_sum = 0;
_lastValidValue = 0;
Value = default;
_index = _hotIndex = 0;
_lastAddedValue = 0;
}
public TValue Update(TValue input, bool isNew = true) {
if (!input.IsHot && isNew) { _hotIndex++; }
if (double.IsNaN(input.Value) || double.IsInfinity(input.Value)) {
Value = new TValue(input.Time, _lastValidValue, isNew, _index > _period);
Pub?.Invoke(this, Value);
return Value;
}
if (IsNew) {
// starting a new bar, fresh calc
index++;
} else {
// updating existing bar, recalc
}
double ma = Input.Value;
if (isNew) {
if (_buffer.Count == _buffer.Capacity) {
_sum -= _buffer[0];
}
_buffer.Add(input.Value, true);
_sum += input.Value;
_lastAddedValue = input.Value;
_index++;
} else {
_sum = _sum - _lastAddedValue + input.Value;
_buffer[_buffer.Count - 1] = input.Value;
_lastAddedValue = input.Value;
}
this.Value = new TValue(Input.Time, ma, IsNew, index > period);
return this.Value;
double result = _sum / _buffer.Count;
_lastValidValue = result;
Value = new TValue(input.Time, result, isNew, _index > (_period + _hotIndex));
Pub?.Invoke(this, Value);
return Value;
}
public void Sub(object source, TValue arg) {
Update(arg);
}
public event Signal Pub;
}
#!csharp
//public delegate void Signal(object source, TValue args);
public class SMA
{
private readonly int _period;
private int _index, _hotIndex;
public TValue Value { get; private set; }
public bool IsHot => _index >= _period;
public int Period => Math.Min(_index, _period);
private double _sum;
private double _lastValidSMA;
private CircularBuffer _buffer;
private double _lastAddedValue;
public SMA(int period) {
_period = period;
Init();
}
public SMA(object source, int period) : this(period) {
var sourceType = source.GetType();
var updateMethod = sourceType.GetMethod("Update", new[] { typeof(TValue) });
if (updateMethod != null) {
var pubEvent = sourceType.GetEvent("Pub");
if (pubEvent != null && pubEvent.EventHandlerType == typeof(Signal)) {
pubEvent.AddEventHandler(source, new Signal(Sub));
} else {
throw new ArgumentException("Source object must have a Pub event of type NewValue.");
}
} else {
throw new ArgumentException("Source object must have an Update(TValue) method.");
}
}
public void Init() {
_buffer = new CircularBuffer(_period);
_sum = 0;
_lastValidSMA = 0;
Value = default;
_index = _hotIndex = 0;
_lastAddedValue = 0;
}
public TValue Update(TValue input) {
if (!input.IsHot && input.IsNew) { _hotIndex++; }
if (double.IsNaN(input.Value) || double.IsInfinity(input.Value)) {
Value = new TValue(input.Time, _lastValidSMA, input.IsNew, _index > _period);
Pub?.Invoke(this, Value);
return Value;
}
if (input.IsNew) {
if (_buffer.Count == _buffer.Capacity) {
_sum -= _buffer[0];
}
_buffer.Add(input.Value, true);
_sum += input.Value;
_lastAddedValue = input.Value;
_index++;
} else {
_sum = _sum - _lastAddedValue + input.Value;
_buffer[_buffer.Count - 1] = input.Value;
_lastAddedValue = input.Value;
}
double sma = _sum / _buffer.Count;
_lastValidSMA = sma;
Value = new TValue(input.Time, sma, input.IsNew, _index > (_period + _hotIndex));
Pub?.Invoke(this, Value);
return Value;
}
public void Sub(object source, TValue arg) {
Update(arg);
}
public event Signal Pub;
}
#!csharp
public class EMA
{
private readonly int _period;
private int _index, _hotIndex;
public TValue Value { 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) {
_period = period;
Init();
}
public EMA(object source, int period) : this(period) {
var sourceType = source.GetType();
var updateMethod = sourceType.GetMethod("Update", new[] { typeof(TValue) });
if (updateMethod != null) {
var pubEvent = sourceType.GetEvent("Pub");
if (pubEvent != null && pubEvent.EventHandlerType == typeof(Signal)) {
pubEvent.AddEventHandler(source, new Signal(Sub));
} else {
throw new ArgumentException("Source object must have a Pub event of type NewValue.");
}
} else {
throw new ArgumentException("Source object must have an Update(TValue) method.");
}
}
public void Init() {
Value = default;
_index = _hotIndex = 0;
_k = 2.0 / (_period + 1);
_lastEMA = 0;
_lastEMACandidate = 0;
}
public TValue Update(TValue input) {
if (!input.IsHot && input.IsNew) { _hotIndex++; }
if (double.IsNaN(input.Value) || double.IsInfinity(input.Value)) {
Value = new TValue(input.Time, _lastEMA, input.IsNew, _index > _period);
Pub?.Invoke(this, Value);
return Value;
}
if (input.IsNew) {
if (_index < 1) { _lastEMA = input.Value; }
_lastEMACandidate = _lastEMA;
_index++;
} else {
if (_index <= 1) { _lastEMACandidate = input.Value; }
_lastEMA = _lastEMACandidate;
}
double kk = (_index <= _period) ? (2.0 / (_index + 1)) : _k;
double ema = (input.Value - _lastEMA) * kk + _lastEMA;
_lastEMA = ema;
Value = new TValue(input.Time, ema, input.IsNew, _index > (_period + _hotIndex));
Pub?.Invoke(this, Value);
return Value;
}
public void Sub(object source, TValue arg) {
Update(arg);
}
public event Signal Pub;
}
#!csharp
EMA ma = new(3);
SMA ma1 = new(ma, 3);
Console.WriteLine($"{"Close",5} {"MA()",10}");
for (int i = 1; i < 10; i=i+1)
{
//ma.Update(100,true);
ma.Update(10,true);
ma.Update(i,false);
Console.WriteLine($"{i} {(double)ma.Value,10:F2} {ma.Value.IsNew}");
TValue tv = new(DateTime.Now, 1000, IsNew: true);
ma.Update(tv);
tv = new(DateTime.Now, i, IsNew: false);
ma.Update(tv);
Console.WriteLine($"{i} {(double)ma.Value,10:F2} {(double)ma1.Value,10:F2} {ma1.Value.IsHot}");
}
#!csharp