mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-31 10:57:43 +00:00
060649192f
- Remove 'C# Implementation Considerations' sections from 34 indicator .md files - Delete 29 temp PowerShell scripts (_fix_mojibake.ps1, _hex_scan.ps1, etc.) - Move test files into tests/ subdirectories for consistent project structure - Add trader-focused bullet points to indicator documentation
512 lines
14 KiB
C#
512 lines
14 KiB
C#
|
|
namespace QuanTAlib.Tests;
|
|
|
|
public class TBarTests
|
|
{
|
|
[Fact]
|
|
public void Constructor_SetsPropertiesCorrectly()
|
|
{
|
|
long time = DateTime.UtcNow.Ticks;
|
|
const double open = 100;
|
|
const double high = 110;
|
|
const double low = 90;
|
|
const double close = 105;
|
|
const double volume = 1000;
|
|
|
|
var bar = new TBar(time, open, high, low, close, volume);
|
|
|
|
Assert.Equal(time, bar.Time);
|
|
Assert.Equal(open, bar.Open);
|
|
Assert.Equal(high, bar.High);
|
|
Assert.Equal(low, bar.Low);
|
|
Assert.Equal(close, bar.Close);
|
|
Assert.Equal(volume, bar.Volume);
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_WithDateTime_SetsPropertiesCorrectly()
|
|
{
|
|
var dateTime = new DateTime(2024, 6, 15, 10, 30, 0, DateTimeKind.Utc);
|
|
const double open = 100;
|
|
const double high = 110;
|
|
const double low = 90;
|
|
const double close = 105;
|
|
const double volume = 1000;
|
|
|
|
var bar = new TBar(dateTime, open, high, low, close, volume);
|
|
|
|
Assert.Equal(dateTime.Ticks, bar.Time);
|
|
Assert.Equal(open, bar.Open);
|
|
Assert.Equal(high, bar.High);
|
|
Assert.Equal(low, bar.Low);
|
|
Assert.Equal(close, bar.Close);
|
|
Assert.Equal(volume, bar.Volume);
|
|
}
|
|
|
|
[Fact]
|
|
public void AsDateTime_ReturnsCorrectDateTime()
|
|
{
|
|
var dateTime = new DateTime(2024, 6, 15, 10, 30, 0, DateTimeKind.Utc);
|
|
var bar = new TBar(dateTime, 100, 110, 90, 105, 1000);
|
|
|
|
Assert.Equal(dateTime, bar.AsDateTime);
|
|
Assert.Equal(DateTimeKind.Utc, bar.AsDateTime.Kind);
|
|
}
|
|
|
|
[Fact]
|
|
public void O_Property_ReturnsTValueWithOpenPrice()
|
|
{
|
|
long time = DateTime.UtcNow.Ticks;
|
|
var bar = new TBar(time, 100, 110, 90, 105, 1000);
|
|
|
|
TValue o = bar.O;
|
|
|
|
Assert.Equal(time, o.Time);
|
|
Assert.Equal(100.0, o.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void H_Property_ReturnsTValueWithHighPrice()
|
|
{
|
|
long time = DateTime.UtcNow.Ticks;
|
|
var bar = new TBar(time, 100, 110, 90, 105, 1000);
|
|
|
|
TValue h = bar.H;
|
|
|
|
Assert.Equal(time, h.Time);
|
|
Assert.Equal(110.0, h.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void L_Property_ReturnsTValueWithLowPrice()
|
|
{
|
|
long time = DateTime.UtcNow.Ticks;
|
|
var bar = new TBar(time, 100, 110, 90, 105, 1000);
|
|
|
|
TValue l = bar.L;
|
|
|
|
Assert.Equal(time, l.Time);
|
|
Assert.Equal(90.0, l.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void C_Property_ReturnsTValueWithClosePrice()
|
|
{
|
|
long time = DateTime.UtcNow.Ticks;
|
|
var bar = new TBar(time, 100, 110, 90, 105, 1000);
|
|
|
|
TValue c = bar.C;
|
|
|
|
Assert.Equal(time, c.Time);
|
|
Assert.Equal(105.0, c.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void V_Property_ReturnsTValueWithVolume()
|
|
{
|
|
long time = DateTime.UtcNow.Ticks;
|
|
var bar = new TBar(time, 100, 110, 90, 105, 1000);
|
|
|
|
TValue v = bar.V;
|
|
|
|
Assert.Equal(time, v.Time);
|
|
Assert.Equal(1000.0, v.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void HL2_CalculatesCorrectly()
|
|
{
|
|
var bar = new TBar(0, 100, 110, 90, 105, 1000);
|
|
Assert.Equal(100.0, bar.HL2);
|
|
}
|
|
|
|
[Fact]
|
|
public void OC2_CalculatesCorrectly()
|
|
{
|
|
var bar = new TBar(0, 100, 110, 90, 104, 1000);
|
|
Assert.Equal(102.0, bar.OC2);
|
|
}
|
|
|
|
[Fact]
|
|
public void OHL3_CalculatesCorrectly()
|
|
{
|
|
var bar = new TBar(0, 100, 110, 90, 105, 1000);
|
|
Assert.Equal(100.0, bar.OHL3);
|
|
}
|
|
|
|
[Fact]
|
|
public void HLC3_CalculatesCorrectly()
|
|
{
|
|
var bar = new TBar(0, 100, 110, 90, 100, 1000);
|
|
Assert.Equal(100.0, bar.HLC3);
|
|
}
|
|
|
|
[Fact]
|
|
public void OHLC4_CalculatesCorrectly()
|
|
{
|
|
var bar = new TBar(0, 100, 110, 90, 100, 1000);
|
|
Assert.Equal(100.0, bar.OHLC4);
|
|
}
|
|
|
|
[Fact]
|
|
public void HLCC4_CalculatesCorrectly()
|
|
{
|
|
var bar = new TBar(0, 100, 110, 90, 100, 1000);
|
|
Assert.Equal(100.0, bar.HLCC4);
|
|
}
|
|
|
|
[Fact]
|
|
public void ImplicitConversion_ToDouble_ReturnsClosePrice()
|
|
{
|
|
var bar = new TBar(0, 100, 110, 90, 105, 1000);
|
|
double closePrice = bar;
|
|
Assert.Equal(105.0, closePrice);
|
|
}
|
|
|
|
[Fact]
|
|
public void ImplicitConversion_ToTValue_ReturnsClosePriceWithTime()
|
|
{
|
|
long time = DateTime.UtcNow.Ticks;
|
|
var bar = new TBar(time, 100, 110, 90, 105, 1000);
|
|
|
|
TValue tv = bar;
|
|
|
|
Assert.Equal(time, tv.Time);
|
|
Assert.Equal(105.0, tv.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void ImplicitConversion_ToDateTime_ReturnsCorrectDateTime()
|
|
{
|
|
var dateTime = new DateTime(2024, 6, 15, 10, 30, 0, DateTimeKind.Utc);
|
|
var bar = new TBar(dateTime, 100, 110, 90, 105, 1000);
|
|
|
|
DateTime result = bar;
|
|
|
|
Assert.Equal(dateTime, result);
|
|
Assert.Equal(DateTimeKind.Utc, result.Kind);
|
|
}
|
|
|
|
[Fact]
|
|
public void ToString_ReturnsFormattedString()
|
|
{
|
|
var dateTime = new DateTime(2024, 6, 15, 10, 30, 0, DateTimeKind.Utc);
|
|
var bar = new TBar(dateTime, 100.5, 110.25, 90.75, 105.0, 1000.0);
|
|
|
|
string result = bar.ToString();
|
|
|
|
Assert.Contains("2024-06-15", result, StringComparison.Ordinal);
|
|
Assert.Contains("10:30:00", result, StringComparison.Ordinal);
|
|
Assert.Contains("O=100.50", result, StringComparison.Ordinal);
|
|
Assert.Contains("H=110.25", result, StringComparison.Ordinal);
|
|
Assert.Contains("L=90.75", result, StringComparison.Ordinal);
|
|
Assert.Contains("C=105.00", result, StringComparison.Ordinal);
|
|
Assert.Contains("V=1000.00", result, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void Equals_TBar_SameBars_ReturnsTrue()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
|
|
Assert.True(bar1.Equals(bar2));
|
|
}
|
|
|
|
[Fact]
|
|
public void Equals_TBar_DifferentTime_ReturnsFalse()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12346, 100, 110, 90, 105, 1000);
|
|
|
|
Assert.False(bar1.Equals(bar2));
|
|
}
|
|
|
|
[Fact]
|
|
public void Equals_TBar_DifferentOpen_ReturnsFalse()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12345, 101, 110, 90, 105, 1000);
|
|
|
|
Assert.False(bar1.Equals(bar2));
|
|
}
|
|
|
|
[Fact]
|
|
public void Equals_TBar_DifferentHigh_ReturnsFalse()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12345, 100, 111, 90, 105, 1000);
|
|
|
|
Assert.False(bar1.Equals(bar2));
|
|
}
|
|
|
|
[Fact]
|
|
public void Equals_TBar_DifferentLow_ReturnsFalse()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12345, 100, 110, 91, 105, 1000);
|
|
|
|
Assert.False(bar1.Equals(bar2));
|
|
}
|
|
|
|
[Fact]
|
|
public void Equals_TBar_DifferentClose_ReturnsFalse()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12345, 100, 110, 90, 106, 1000);
|
|
|
|
Assert.False(bar1.Equals(bar2));
|
|
}
|
|
|
|
[Fact]
|
|
public void Equals_TBar_DifferentVolume_ReturnsFalse()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12345, 100, 110, 90, 105, 1001);
|
|
|
|
Assert.False(bar1.Equals(bar2));
|
|
}
|
|
|
|
[Fact]
|
|
public void Equals_Object_SameTBar_ReturnsTrue()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
object bar2 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
|
|
Assert.True(bar1.Equals(bar2));
|
|
}
|
|
|
|
[Fact]
|
|
public void Equals_Object_DifferentType_ReturnsFalse()
|
|
{
|
|
var bar = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
object other = "not a TBar";
|
|
|
|
Assert.False(bar.Equals(other));
|
|
}
|
|
|
|
[Fact]
|
|
public void Equals_Object_Null_ReturnsFalse()
|
|
{
|
|
var bar = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
|
|
Assert.False(bar.Equals(null));
|
|
}
|
|
|
|
[Fact]
|
|
public void GetHashCode_SameBars_ReturnsSameHashCode()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
|
|
Assert.Equal(bar1.GetHashCode(), bar2.GetHashCode());
|
|
}
|
|
|
|
[Fact]
|
|
public void GetHashCode_DifferentBars_ReturnsDifferentHashCode()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12346, 100, 110, 90, 105, 1000);
|
|
|
|
Assert.NotEqual(bar1.GetHashCode(), bar2.GetHashCode());
|
|
}
|
|
|
|
[Fact]
|
|
public void EqualityOperator_SameBars_ReturnsTrue()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
|
|
Assert.True(bar1 == bar2);
|
|
}
|
|
|
|
[Fact]
|
|
public void EqualityOperator_DifferentBars_ReturnsFalse()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12346, 100, 110, 90, 105, 1000);
|
|
|
|
Assert.False(bar1 == bar2);
|
|
}
|
|
|
|
[Fact]
|
|
public void InequalityOperator_SameBars_ReturnsFalse()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
|
|
Assert.False(bar1 != bar2);
|
|
}
|
|
|
|
[Fact]
|
|
public void InequalityOperator_DifferentBars_ReturnsTrue()
|
|
{
|
|
var bar1 = new TBar(12345, 100, 110, 90, 105, 1000);
|
|
var bar2 = new TBar(12346, 100, 110, 90, 105, 1000);
|
|
|
|
Assert.True(bar1 != bar2);
|
|
}
|
|
|
|
// Additional edge case tests
|
|
[Fact]
|
|
public void Constructor_WithLocalDateTime_ConvertsToUtc()
|
|
{
|
|
var localDateTime = new DateTime(2024, 6, 15, 10, 30, 0, DateTimeKind.Local);
|
|
var bar = new TBar(localDateTime, 100, 110, 90, 105, 1000);
|
|
|
|
// AsDateTime should return UTC
|
|
Assert.Equal(DateTimeKind.Utc, bar.AsDateTime.Kind);
|
|
Assert.Equal(localDateTime.ToUniversalTime().Ticks, bar.Time);
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_WithUnspecifiedDateTime_ConvertsToUtc()
|
|
{
|
|
var unspecifiedDateTime = new DateTime(2024, 6, 15, 10, 30, 0, DateTimeKind.Unspecified);
|
|
var bar = new TBar(unspecifiedDateTime, 100, 110, 90, 105, 1000);
|
|
|
|
// Should be converted to UTC
|
|
Assert.Equal(DateTimeKind.Utc, bar.AsDateTime.Kind);
|
|
}
|
|
|
|
[Fact]
|
|
public void DefaultTBar_HasZeroValues()
|
|
{
|
|
var bar = default(TBar);
|
|
|
|
Assert.Equal(0, bar.Time);
|
|
Assert.Equal(0.0, bar.Open);
|
|
Assert.Equal(0.0, bar.High);
|
|
Assert.Equal(0.0, bar.Low);
|
|
Assert.Equal(0.0, bar.Close);
|
|
Assert.Equal(0.0, bar.Volume);
|
|
}
|
|
|
|
[Fact]
|
|
public void TBar_WithNaN_HandlesGracefully()
|
|
{
|
|
var bar = new TBar(12345, double.NaN, 110, 90, 105, 1000);
|
|
|
|
Assert.True(double.IsNaN(bar.Open));
|
|
Assert.True(double.IsNaN(bar.O.Value));
|
|
Assert.True(double.IsNaN(bar.OHL3)); // Uses Open
|
|
Assert.True(double.IsNaN(bar.OC2)); // Uses Open
|
|
Assert.True(double.IsNaN(bar.OHLC4)); // Uses Open
|
|
}
|
|
|
|
[Fact]
|
|
public void TBar_WithPositiveInfinity_HandlesGracefully()
|
|
{
|
|
var bar = new TBar(12345, 100, double.PositiveInfinity, 90, 105, 1000);
|
|
|
|
Assert.True(double.IsPositiveInfinity(bar.High));
|
|
Assert.True(double.IsPositiveInfinity(bar.H.Value));
|
|
Assert.True(double.IsPositiveInfinity(bar.HL2)); // Uses High
|
|
}
|
|
|
|
[Fact]
|
|
public void TBar_WithNegativeInfinity_HandlesGracefully()
|
|
{
|
|
var bar = new TBar(12345, 100, 110, double.NegativeInfinity, 105, 1000);
|
|
|
|
Assert.True(double.IsNegativeInfinity(bar.Low));
|
|
Assert.True(double.IsNegativeInfinity(bar.L.Value));
|
|
Assert.True(double.IsNegativeInfinity(bar.HL2)); // Uses Low
|
|
Assert.True(double.IsNegativeInfinity(bar.HLC3)); // Uses Low
|
|
}
|
|
|
|
[Fact]
|
|
public void TBar_WithMaxValue_HandlesGracefully()
|
|
{
|
|
var bar = new TBar(12345, double.MaxValue, double.MaxValue, double.MinValue, 105, 1000);
|
|
|
|
Assert.Equal(double.MaxValue, bar.Open);
|
|
Assert.Equal(double.MaxValue, bar.High);
|
|
Assert.Equal(double.MinValue, bar.Low);
|
|
// HL2 = (MaxValue + MinValue) * 0.5 = 0 (symmetric around zero)
|
|
Assert.Equal(0.0, bar.HL2);
|
|
}
|
|
|
|
[Fact]
|
|
public void TBar_WithEpsilon_HandlesGracefully()
|
|
{
|
|
var bar = new TBar(12345, double.Epsilon, double.Epsilon, double.Epsilon, double.Epsilon, double.Epsilon);
|
|
|
|
Assert.Equal(double.Epsilon, bar.Open);
|
|
Assert.Equal(double.Epsilon, bar.Close);
|
|
Assert.True(bar.HL2 > 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void HL2_WithNegativeValues_CalculatesCorrectly()
|
|
{
|
|
var bar = new TBar(0, -100, -90, -110, -95, 1000);
|
|
|
|
Assert.Equal(-100.0, bar.HL2); // (-90 + -110) / 2
|
|
}
|
|
|
|
[Fact]
|
|
public void OHLC4_WithNegativeValues_CalculatesCorrectly()
|
|
{
|
|
var bar = new TBar(0, -100, -90, -110, -100, 1000);
|
|
|
|
Assert.Equal(-100.0, bar.OHLC4); // (-100 + -90 + -110 + -100) / 4
|
|
}
|
|
|
|
[Fact]
|
|
public void ImplicitConversion_ToTValue_PreservesTimeAndClose()
|
|
{
|
|
const long time = 12_345_678_901_234_567;
|
|
var bar = new TBar(time, 100, 110, 90, 105.5, 1000);
|
|
|
|
TValue tv = bar;
|
|
|
|
Assert.Equal(time, tv.Time);
|
|
Assert.Equal(105.5, tv.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void ToString_WithNaN_DoesNotThrow()
|
|
{
|
|
var bar = new TBar(DateTime.UtcNow.Ticks, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN);
|
|
|
|
string result = bar.ToString();
|
|
|
|
Assert.NotNull(result);
|
|
Assert.Contains("NaN", result, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[Fact]
|
|
public void O_H_L_C_V_AllHaveSameTime()
|
|
{
|
|
long time = DateTime.UtcNow.Ticks;
|
|
var bar = new TBar(time, 100, 110, 90, 105, 1000);
|
|
|
|
Assert.Equal(time, bar.O.Time);
|
|
Assert.Equal(time, bar.H.Time);
|
|
Assert.Equal(time, bar.L.Time);
|
|
Assert.Equal(time, bar.C.Time);
|
|
Assert.Equal(time, bar.V.Time);
|
|
}
|
|
|
|
[Fact]
|
|
public void HLCC4_DoubleWeightsClose()
|
|
{
|
|
// HLCC4 = (High + Low + Close + Close) / 4
|
|
var bar = new TBar(0, 100, 120, 80, 100, 1000);
|
|
|
|
// (120 + 80 + 100 + 100) / 4 = 400 / 4 = 100
|
|
Assert.Equal(100.0, bar.HLCC4);
|
|
}
|
|
|
|
[Fact]
|
|
public void OHL3_ExcludesClose()
|
|
{
|
|
// OHL3 = (Open + High + Low) / 3
|
|
var bar = new TBar(0, 90, 120, 60, 999, 1000);
|
|
|
|
// (90 + 120 + 60) / 3 = 270 / 3 = 90
|
|
Assert.Equal(90.0, bar.OHL3);
|
|
}
|
|
}
|