This commit is contained in:
Miha Kralj
2024-09-30 06:46:07 -07:00
parent 148f0ea846
commit bdc01bff4a
28 changed files with 803 additions and 1053 deletions
-4
View File
@@ -1,4 +0,0 @@
{
"SonarCloudOrganization": "mihakralj",
"ProjectKey": "mihakralj_QuanTAlib"
}
+13
View File
@@ -0,0 +1,13 @@
{
"sonarlint.connectedMode.connections.sonarcloud": [
{
"organizationKey": "mihakralj",
"token": "6df7cd62a17dc4e1c5532df1da2f49d5a977dd50",
"connectionId": "mihakralj"
}
],
"sonarlint.connectedMode.project": {
"connectionId": "mihakralj",
"projectKey": "mihakralj_QuanTAlib"
}
}
+1
View File
@@ -35,6 +35,7 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.DotNet.Interactive.Formatting" Version="1.0.0-beta.21459.1" />
</ItemGroup> </ItemGroup>
<PropertyGroup Condition="'$(IsLocalBuild)' == 'true'"> <PropertyGroup Condition="'$(IsLocalBuild)' == 'true'">
+46 -35
View File
@@ -1,57 +1,68 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59 VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "quantalib", "lib\quantalib.csproj", "{584E06A9-CEB4-476A-85CC-6A8FF3974AE2}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "benchmark", "benchmark\benchmark.csproj", "{DBB674D9-43AA-4383-A4D0-E791847C7145}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{D85FEBB4-B651-466F-85CC-FD902378D4D2}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "quantalib", "lib\quantalib.csproj", "{D2F742C0-9E2A-4B07-8D9F-0DF0BA3DDA31}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MovingAverages", "quantower\Averages\Averages.csproj", "{32CC09CC-26E3-4FCE-8932-C0513C4AD766}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SyntheticVendor", "SyntheticVendor\SyntheticVendor.csproj", "{1777C7BB-F67A-4F00-99BB-EE48178A7129}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntheticVendor", "SyntheticVendor\SyntheticVendor.csproj", "{20B1B5F1-8C36-4668-B0AE-951C13AE197B}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "tests\Tests.csproj", "{A89D1A5D-9DB9-4E5D-A7D6-E153509430CD}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "quantower", "quantower", "{A8D9AE68-24E3-476C-BB98-244541BB4B43}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "quantower", "quantower", "{1EC1B338-6AD9-4E3D-82C3-6591CC148DD5}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Statistics", "quantower\Statistics\Statistics.csproj", "{B6D3EB11-63B6-430F-B526-E1981B3D8214}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Averages", "quantower\Averages\Averages.csproj", "{61AFF1E5-9E2B-47F4-9665-D8358C5BDD6F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "benchmark", "benchmark\benchmark.csproj", "{6629C6D2-FC34-4BDF-AEF4-A5859E05981E}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Statistics", "quantower\Statistics\Statistics.csproj", "{7EBB6ECD-15FA-44DD-B231-FED97E0B710D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volatility", "quantower\Volatility\Volatility.csproj", "{9190CFDD-9FD8-4E14-9269-79325B03EC6C}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DBB674D9-43AA-4383-A4D0-E791847C7145}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DBB674D9-43AA-4383-A4D0-E791847C7145}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DBB674D9-43AA-4383-A4D0-E791847C7145}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DBB674D9-43AA-4383-A4D0-E791847C7145}.Release|Any CPU.Build.0 = Release|Any CPU
{D2F742C0-9E2A-4B07-8D9F-0DF0BA3DDA31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D2F742C0-9E2A-4B07-8D9F-0DF0BA3DDA31}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2F742C0-9E2A-4B07-8D9F-0DF0BA3DDA31}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2F742C0-9E2A-4B07-8D9F-0DF0BA3DDA31}.Release|Any CPU.Build.0 = Release|Any CPU
{1777C7BB-F67A-4F00-99BB-EE48178A7129}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1777C7BB-F67A-4F00-99BB-EE48178A7129}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1777C7BB-F67A-4F00-99BB-EE48178A7129}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1777C7BB-F67A-4F00-99BB-EE48178A7129}.Release|Any CPU.Build.0 = Release|Any CPU
{A89D1A5D-9DB9-4E5D-A7D6-E153509430CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A89D1A5D-9DB9-4E5D-A7D6-E153509430CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A89D1A5D-9DB9-4E5D-A7D6-E153509430CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A89D1A5D-9DB9-4E5D-A7D6-E153509430CD}.Release|Any CPU.Build.0 = Release|Any CPU
{61AFF1E5-9E2B-47F4-9665-D8358C5BDD6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{61AFF1E5-9E2B-47F4-9665-D8358C5BDD6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{61AFF1E5-9E2B-47F4-9665-D8358C5BDD6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{61AFF1E5-9E2B-47F4-9665-D8358C5BDD6F}.Release|Any CPU.Build.0 = Release|Any CPU
{7EBB6ECD-15FA-44DD-B231-FED97E0B710D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7EBB6ECD-15FA-44DD-B231-FED97E0B710D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7EBB6ECD-15FA-44DD-B231-FED97E0B710D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7EBB6ECD-15FA-44DD-B231-FED97E0B710D}.Release|Any CPU.Build.0 = Release|Any CPU
{9190CFDD-9FD8-4E14-9269-79325B03EC6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9190CFDD-9FD8-4E14-9269-79325B03EC6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9190CFDD-9FD8-4E14-9269-79325B03EC6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9190CFDD-9FD8-4E14-9269-79325B03EC6C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{584E06A9-CEB4-476A-85CC-6A8FF3974AE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{584E06A9-CEB4-476A-85CC-6A8FF3974AE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{584E06A9-CEB4-476A-85CC-6A8FF3974AE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{584E06A9-CEB4-476A-85CC-6A8FF3974AE2}.Release|Any CPU.Build.0 = Release|Any CPU
{D85FEBB4-B651-466F-85CC-FD902378D4D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D85FEBB4-B651-466F-85CC-FD902378D4D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D85FEBB4-B651-466F-85CC-FD902378D4D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D85FEBB4-B651-466F-85CC-FD902378D4D2}.Release|Any CPU.Build.0 = Release|Any CPU
{32CC09CC-26E3-4FCE-8932-C0513C4AD766}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32CC09CC-26E3-4FCE-8932-C0513C4AD766}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32CC09CC-26E3-4FCE-8932-C0513C4AD766}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32CC09CC-26E3-4FCE-8932-C0513C4AD766}.Release|Any CPU.Build.0 = Release|Any CPU
{20B1B5F1-8C36-4668-B0AE-951C13AE197B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{20B1B5F1-8C36-4668-B0AE-951C13AE197B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{20B1B5F1-8C36-4668-B0AE-951C13AE197B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20B1B5F1-8C36-4668-B0AE-951C13AE197B}.Release|Any CPU.Build.0 = Release|Any CPU
{B6D3EB11-63B6-430F-B526-E1981B3D8214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B6D3EB11-63B6-430F-B526-E1981B3D8214}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6D3EB11-63B6-430F-B526-E1981B3D8214}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6D3EB11-63B6-430F-B526-E1981B3D8214}.Release|Any CPU.Build.0 = Release|Any CPU
{6629C6D2-FC34-4BDF-AEF4-A5859E05981E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6629C6D2-FC34-4BDF-AEF4-A5859E05981E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6629C6D2-FC34-4BDF-AEF4-A5859E05981E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6629C6D2-FC34-4BDF-AEF4-A5859E05981E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{B6D3EB11-63B6-430F-B526-E1981B3D8214} = {A8D9AE68-24E3-476C-BB98-244541BB4B43} {61AFF1E5-9E2B-47F4-9665-D8358C5BDD6F} = {1EC1B338-6AD9-4E3D-82C3-6591CC148DD5}
{7EBB6ECD-15FA-44DD-B231-FED97E0B710D} = {1EC1B338-6AD9-4E3D-82C3-6591CC148DD5}
{9190CFDD-9FD8-4E14-9269-79325B03EC6C} = {1EC1B338-6AD9-4E3D-82C3-6591CC148DD5}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {080D10E4-B741-4A85-B37B-08845A5C78D9}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal
+4 -1
View File
@@ -540,7 +540,10 @@ namespace SyntheticVendorNamespace
openValue = 0.0001; openValue = 0.0001;
closeValue = 100; closeValue = 100;
} }
else { } else
{
// No action
}
return new HistoryItemBar return new HistoryItemBar
{ {
-857
View File
@@ -1,857 +0,0 @@
using Xunit;
namespace QuanTAlib;
public class Consistency
{
Random rnd;
int series_len = 1000;
int corrections = 100;
public Consistency()
{ //constructor
rnd = new((int)DateTime.Now.Ticks);
}
[Fact]
public void CanUpdate()
{
GbmFeed gbm = new();
TSeries input = new(gbm.Close);
TSeries output = new(input);
gbm.Add(10000);
Assert.Equal(input.Count, output.Count);
for (int i = 0; i < input.Count; i++)
{
Assert.Equal(input[i].v, output[i].v);
}
}
[Fact]
public void Alma_isNew()
{
int p = (int)rnd.Next(2, 100);
double offset = rnd.Next();
double sigma = rnd.Next(1, 100);
Alma ma1 = new(period: p, offset: offset, sigma: sigma);
Alma ma2 = new(period: p, offset: offset, sigma: sigma);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Convolution_isNew()
{
Convolution ma1 = new(new double[] { 1.0, 2, 3, 2, 1 });
Convolution ma2 = new(new double[] { 1.0, 2, 3, 2, 1 });
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Dema_isNew()
{
int p = (int)rnd.Next(2, 100);
Dema ma1 = new(p);
Dema ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Dsma_isNew()
{
int p = (int)rnd.Next(2, 100);
Dsma ma1 = new(p);
Dsma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Dwma_isNew()
{
int p = (int)rnd.Next(2, 100);
Dwma ma1 = new(p);
Dwma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void EmaSma_isNew()
{
int p = (int)rnd.Next(2, 100);
Ema ma1 = new(p, useSma: true);
Ema ma2 = new(p, useSma: true);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Ema_isNew()
{
int p = (int)rnd.Next(2, 100);
Ema ma1 = new(p, useSma: false);
Ema ma2 = new(p, useSma: false);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Sma_isNew()
{
int p = (int)rnd.Next(2, 100);
Sma ma1 = new(p);
Sma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Epma_isNew()
{
int p = (int)rnd.Next(2, 100);
Epma ma1 = new(p);
Epma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Frama_isNew()
{
int p = (int)rnd.Next(2, 100);
Frama ma1 = new(p);
Frama ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Fwma_isNew()
{
int p = (int)rnd.Next(2, 100);
Fwma ma1 = new(p);
Fwma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Gma_isNew()
{
int p = (int)rnd.Next(2, 100);
Gma ma1 = new(p);
Gma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Hma_isNew()
{
int p = (int)rnd.Next(2, 100);
Hma ma1 = new(p);
Hma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Hwma_isNew()
{
int p = (int)rnd.Next(2, 100);
Hwma ma1 = new(p);
Hwma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Kama_isNew()
{
int p = (int)rnd.Next(2, 100);
Kama ma1 = new(p);
Kama ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Ltma_isNew()
{
int p = rnd.Next(0, 1);
Ltma ma1 = new(p);
Ltma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Mama_isNew()
{
int p = rnd.Next(0, 1);
Mama ma1 = new(p, p * 0.1);
Mama ma2 = new(p, p * 0.1);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
Assert.True(ma1.Value == ma2.Value, $"Assertion failed for p={p}, i={i}. Expected {ma1.Value} but got {ma2.Value}.");
}
}
[Fact]
public void Mgdi_isNew()
{
int p = (int)rnd.Next(2, 100);
Mgdi ma1 = new(p);
Mgdi ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Mma_isNew()
{
int p = (int)rnd.Next(2, 100);
Mma ma1 = new(p);
Mma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Qema_isNew()
{
Qema ma1 = new();
Qema ma2 = new();
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Rema_isNew()
{
int p = (int)rnd.Next(2, 100);
Rema ma1 = new(p);
Rema ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Rma_isNew()
{
int p = (int)rnd.Next(2, 100);
Rma ma1 = new(p);
Rma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Sinema_isNew()
{
int p = (int)rnd.Next(2, 100);
Sinema ma1 = new(p);
Sinema ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Smma_isNew()
{
int p = (int)rnd.Next(2, 100);
Smma ma1 = new(p);
Smma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void T3_isNew()
{
int p = (int)rnd.Next(2, 100);
T3 ma1 = new(p);
T3 ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Tema_isNew()
{
int p = (int)rnd.Next(2, 100);
Tema ma1 = new(p);
Tema ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Trima_isNew()
{
int p = (int)rnd.Next(2, 100);
Trima ma1 = new(p);
Trima ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Vidya_isNew()
{
int p = (int)rnd.Next(2, 100);
Vidya ma1 = new(p);
Vidya ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Wma_isNew()
{
int p = (int)rnd.Next(2, 100);
Wma ma1 = new(p);
Wma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Zlema_isNew()
{
int p = (int)rnd.Next(2, 100);
Zlema ma1 = new(p);
Zlema ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Entropy_isNew()
{
int p = (int)rnd.Next(2, 100);
Entropy ma1 = new(p);
Entropy ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Kurtosis_isNew()
{
int p = (int)rnd.Next(5, 100);
Kurtosis ma1 = new(p);
Kurtosis ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Max_isNew()
{
int p = (int)rnd.Next(2, 100);
Max ma1 = new(p, 0.01);
Max ma2 = new(p, 0.01);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Min_isNew()
{
int p = (int)rnd.Next(2, 100);
Min ma1 = new(p, 0.01);
Min ma2 = new(p, 0.01);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Med_isNew()
{
int p = (int)rnd.Next(2, 100);
Median ma1 = new(p);
Median ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Mode_isNew()
{
int p = (int)rnd.Next(2, 100);
Mode ma1 = new(p);
Mode ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Percentile_isNew()
{
int p = (int)rnd.Next(2, 100);
Percentile ma1 = new(p, 50);
Percentile ma2 = new(p, 50);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Skew_isNew()
{
int p = (int)rnd.Next(2, 100);
Skew ma1 = new(p);
Skew ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Stddev_isNew()
{
int p = (int)rnd.Next(2, 100);
Stddev ma1 = new(p);
Stddev ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Variance_isNew()
{
int p = (int)rnd.Next(2, 100);
Variance ma1 = new(p);
Variance ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Zscore_isNew()
{
int p = (int)rnd.Next(2, 100);
Zscore ma1 = new(p);
Zscore ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
}
+58
View File
@@ -0,0 +1,58 @@
using Xunit;
using System.Reflection;
namespace QuanTAlib
{
public class BarIndicatorTests
{
private Random rnd;
private const int SeriesLen = 1000;
private const int Corrections = 100;
public BarIndicatorTests()
{
rnd = new Random((int)DateTime.Now.Ticks);
}
private static readonly iTValue[] indicators = new iTValue[]
{
new Atr(period: 14),
};
[Theory]
[MemberData(nameof(GetIndicators))]
public void IndicatorIsNew(iTValue indicator)
{
var indicator1 = indicator;
var indicator2 = indicator;
MethodInfo calcMethod = indicator.GetType().GetMethod("Calc")!;
if (calcMethod == null)
{
throw new Exception($"Calc method not found for indicator type: {indicator.GetType().Name}");
}
for (int i = 0; i < SeriesLen; i++)
{
TBar item1 = new(Time: DateTime.Now, Open: rnd.Next(-100, 100), High: rnd.Next(-100, 100), Low: rnd.Next(-100, 100), Close: rnd.Next(-100, 100), Volume: rnd.Next(-1000, 1000), IsNew: true);
calcMethod.Invoke(indicator1, new object[] { item1 });
for (int j = 0; j < Corrections; j++)
{
item1 = new(Time: DateTime.Now, Open: rnd.Next(-100, 100), High: rnd.Next(-100, 100), Low: rnd.Next(-100, 100), Close: rnd.Next(-100, 100), Volume: rnd.Next(-1000, 1000), IsNew: false);
calcMethod.Invoke(indicator1, new object[] { item1 });
}
var item2 = new TBar (item1.Time, item1.Open, item1.High, item1.Low, item1.Close, item1.Volume , IsNew: true);
calcMethod.Invoke(indicator2, new object[] { item2 });
Assert.Equal(indicator1.Value, indicator2.Value);
}
}
public static IEnumerable<object[]> GetIndicators()
{
return indicators.Select(indicator => new object[] { indicator });
}
}
}
+97
View File
@@ -0,0 +1,97 @@
using Xunit;
using System.Reflection;
namespace QuanTAlib
{
public class IndicatorTests
{
private Random rnd;
private const int SeriesLen = 1000;
private const int Corrections = 100;
public IndicatorTests()
{
rnd = new Random((int)DateTime.Now.Ticks);
}
private static readonly iTValue[] indicators =
[
new Ema(period: 10, useSma: true),
new Alma(period: 14, offset: 0.85, sigma: 6),
new Convolution(new double[] { 1.0, 2, 3, 2, 1 }),
new Dema(period: 14),
new Dsma(period: 14),
new Dwma(period: 14),
new Epma(period: 14),
new Frama(period: 14),
new Fwma(period: 14),
new Gma(period: 14),
new Hma(period: 14),
new Hwma(period: 14),
new Kama(period: 14),
new Mama(fastLimit: 0.5, slowLimit: 0.05),
new Mgdi(period: 14),
new Mma(period: 14),
new Qema(),
new Rema(period: 14),
new Rma(period: 14),
new Sinema(period: 14),
new Sma(period: 14),
new Smma(period: 14),
new T3(period: 14),
new Tema(period: 14),
new Trima(period: 14),
new Vidya(shortPeriod: 14, longPeriod: 30, alpha: 0.2),
new Wma(period: 14),
new Zlema(period: 14),
new Entropy(period: 14),
new Kurtosis(period: 14),
new Max(period: 14, decay: 0.01),
new Min(period: 14, decay: 0.01),
new Median(period: 14),
new Mode(period: 14),
new Percentile(period: 14, percent: 50),
new Skew(period: 14),
new Stddev(period: 14),
new Variance(period: 14),
new Zscore(period: 14)
];
[Theory]
[MemberData(nameof(GetIndicators))]
public void IndicatorIsNew(iTValue indicator)
{
var indicator1 = indicator;
var indicator2 = indicator;
MethodInfo calcMethod = indicator.GetType().GetMethod("Calc")!;
if (calcMethod == null)
{
throw new Exception($"Calc method not found for indicator type: {indicator.GetType().Name}");
}
for (int i = 0; i < SeriesLen; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
calcMethod.Invoke(indicator1, new object[] { item1 });
for (int j = 0; j < Corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
calcMethod.Invoke(indicator1, new object[] { item1 });
}
var item2 = new TValue(item1.Time, item1.Value, IsNew: true);
calcMethod.Invoke(indicator2, new object[] { item2 });
Assert.Equal(indicator1.Value, indicator2.Value);
}
}
public static IEnumerable<object[]> GetIndicators()
{
return indicators.Select(indicator => new object[] { indicator });
}
}
}
+20
View File
@@ -320,4 +320,24 @@ public class SkenderTests
} }
} }
[Fact]
public void ATR()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Atr ma = new(period: period);
TSeries QL = new();
foreach (TBar item in bars) { QL.Add(ma.Calc(item)); }
var SK = quotes.GetAtr(lookbackPeriods: period).Select(i => i.Atr.Null2NaN()!);
Assert.Equal(QL.Length, QL.Length);
for (int i = QL.Length - 1; i > period +500; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
} }
+5
View File
@@ -0,0 +1,5 @@
# Backlog and done
|**QT**|**Cht**|Cmnt|Docs|isNew|Valid|
|--|:--:|:--:|:--:|:--:|:--:|
|AFIRMA|✔️|||||
+31 -3
View File
@@ -8,6 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-simple-dark.css" integrity="sha384-G+RAlt+LEfAH/nY+DZh3+XIhRboypMI32hiJ9BwnmjF41May5BWQKyrDrEkNdV/i" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-simple-dark.css" integrity="sha384-G+RAlt+LEfAH/nY+DZh3+XIhRboypMI32hiJ9BwnmjF41May5BWQKyrDrEkNdV/i" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.7/dist/katex.min.css" integrity="sha384-3UiQGuEI4TTMaFmGIZumfRPtfKQ3trwQE2JgosJxCnGmQpL/lJdjpcHkaaFwHlcI" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.7/dist/katex.min.css" integrity="sha384-3UiQGuEI4TTMaFmGIZumfRPtfKQ3trwQE2JgosJxCnGmQpL/lJdjpcHkaaFwHlcI" crossorigin="anonymous">
<style> <style>
.markdown-section { .markdown-section {
max-width: none !important; max-width: none !important;
@@ -18,7 +19,7 @@
font-size: 12px; font-size: 12px;
} }
.markdown-section table tbody td { .markdown-section table tbody td {
padding: 4px 1px; padding: 4px 1px;
} }
:root { :root {
--sidebar-width: 350px; --sidebar-width: 350px;
@@ -32,7 +33,34 @@
.sidebar-toggle { .sidebar-toggle {
width: var(--sidebar-width); width: var(--sidebar-width);
} }
/* Updated styles for partially expandable sidebar */
.sidebar-nav ul ul ul ul {
overflow: hidden;
max-height: 0;
transition: max-height 0.3s ease-out;
}
.sidebar-nav ul ul ul li:hover > ul {
max-height: 1000px;
transition: max-height 0.3s ease-in;
}
.sidebar-nav .collapse.level-4 > ul {
max-height: 0 !important;
}
.sidebar-nav .collapse.level-4:hover > ul {
max-height: 1000px !important;
}
.sidebar-nav .folder > .app-sub-sidebar {
display: block !important;
}
/* Ensure levels 1, 2, and 3 are always visible */
.sidebar-nav > ul,
.sidebar-nav > ul > li > ul,
.sidebar-nav > ul > li > ul > li > ul {
max-height: none !important;
overflow: visible !important;
}
</style> </style>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
@@ -40,10 +68,10 @@
window.$docsify = { window.$docsify = {
homepage: 'readme.md', homepage: 'readme.md',
loadSidebar: true, loadSidebar: true,
subMaxLevel: 1, subMaxLevel: 4, // Increased to allow for level 4+ items
name: '', name: '',
repo: '', repo: '',
sidebarDisplayLevel: 2, sidebarDisplayLevel: 3, // Changed to keep levels 1, 2, and 3 expanded
themeable: { themeable: {
readyTransition: true, readyTransition: true,
responsiveTables: true responsiveTables: true
+2 -5
View File
@@ -16,7 +16,8 @@
**Quan**titative **TA** **lib**rary (QuanTAlib) is a C# library of classess and methods for quantitative technical analysis useful for analyzing quotes with [Quantower](https://www.quantower.com/) and other C#-based trading platforms. **Quan**titative **TA** **lib**rary (QuanTAlib) is a C# library of classess and methods for quantitative technical analysis useful for analyzing quotes with [Quantower](https://www.quantower.com/) and other C#-based trading platforms.
[**Visit documentation pages**](https://mihakralj.github.io/QuanTAlib/#/) [**Visit documentation pages**](https://mihakralj.github.io/QuanTAlib/#/)<br>
[**List of indicators - implemented and planned**](indicators/indicators.md)
**QuanTAlib** is a C# library written with some specific design criteria in mind. Here is why there is '_yet another C# TA library_': **QuanTAlib** is a C# library written with some specific design criteria in mind. Here is why there is '_yet another C# TA library_':
@@ -24,10 +25,6 @@
- **Allow updates/corrections** of the last quote - QuanTAlib is re-calculating the last value as many times as required before continuing to the new bar - **Allow updates/corrections** of the last quote - QuanTAlib is re-calculating the last value as many times as required before continuing to the new bar
- **Calculate early data right** - calculated data is as valid as mathematically possible from the first value onwards - no blackout or warming-up periods. All indicators return data from the first bar, alongside with a flag `isHot` - defining if calculation is already stable. - **Calculate early data right** - calculated data is as valid as mathematically possible from the first value onwards - no blackout or warming-up periods. All indicators return data from the first bar, alongside with a flag `isHot` - defining if calculation is already stable.
### Coverage
[List of indicators - implemented and planned](indicators/indicators.md)
## Installation to Quantower ## Installation to Quantower
- `<Quantower_root>` is the directory where Quantower is installed - where `Start.lnk` launcher is - `<Quantower_root>` is the directory where Quantower is installed - where `Start.lnk` launcher is
-89
View File
@@ -1,89 +0,0 @@
namespace QuanTAlib;
public class Ama : AbstractBase
{
private readonly int Period;
private readonly CircularBuffer _buffer;
private readonly double _alpha; // Adaptive factor
private double _lastAfirma, _p_lastAfirma;
private double _lastError, _p_lastError;
public Ama(int period, double alpha = 0.1)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
if (alpha <= 0 || alpha >= 1)
{
throw new ArgumentOutOfRangeException(nameof(alpha), "Alpha must be between 0 and 1 (exclusive).");
}
Period = period;
WarmupPeriod = period;
_buffer = new CircularBuffer(period);
_alpha = alpha;
Name = "Afirma";
WarmupPeriod = period;
Init();
}
public Ama(object source, int period, double alpha = 0.1) : this(period: period, alpha: alpha)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
public override void Init()
{
base.Init();
_lastAfirma = 0;
_lastError = 0;
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
_p_lastAfirma = _lastAfirma;
_p_lastError = _lastError;
}
else
{
_lastAfirma = _p_lastAfirma;
_lastError = _p_lastError;
}
}
/// <summary>
/// Core AFIRMA calculation
/// </summary>
protected override double Calculation()
{
double result;
ManageState(IsNew);
_buffer.Add(Input.Value, Input.IsNew);
if (_index < Period)
{
// Use simple average during warmup period
result = _buffer.Average();
}
else
{
// AFIRMA calculation
double sma = _buffer.Average();
double error = Input.Value - _lastAfirma;
double denominator = Math.Abs(error) + Math.Abs(_lastError);
double adaptiveFactor = denominator != 0 ? _alpha * Math.Abs(error) / denominator : _alpha;
result = sma + adaptiveFactor * (Input.Value - sma);
_lastError = error;
}
_lastAfirma = result;
IsHot = _index >= WarmupPeriod;
return result;
}
}
-1
View File
@@ -40,7 +40,6 @@ public class Mama : AbstractBase
public override void Init() public override void Init()
{ {
Fama = new TValue(); Fama = new TValue();
base.Init();
} }
protected override void ManageState(bool isNew) protected override void ManageState(bool isNew)
+12 -28
View File
@@ -1,7 +1,6 @@
namespace QuanTAlib; namespace QuanTAlib;
public class T3 : AbstractBase public class T3 : AbstractBase {
{
private readonly int _period; private readonly int _period;
private readonly bool _useSma; private readonly bool _useSma;
private readonly double _k, _c1, _c2, _c3, _c4; private readonly double _k, _c1, _c2, _c3, _c4;
@@ -9,10 +8,8 @@ public class T3 : AbstractBase
private double _lastEma1, _lastEma2, _lastEma3, _lastEma4, _lastEma5, _lastEma6; private double _lastEma1, _lastEma2, _lastEma3, _lastEma4, _lastEma5, _lastEma6;
private double _p_lastEma1, _p_lastEma2, _p_lastEma3, _p_lastEma4, _p_lastEma5, _p_lastEma6; private double _p_lastEma1, _p_lastEma2, _p_lastEma3, _p_lastEma4, _p_lastEma5, _p_lastEma6;
public T3(int period, double vfactor = 0.7, bool useSma = true) public T3(int period, double vfactor = 0.7, bool useSma = true) {
{ if (period < 1) {
if (period < 1)
{
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period)); throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
} }
_period = period; _period = period;
@@ -37,15 +34,12 @@ public class T3 : AbstractBase
Init(); Init();
} }
public T3(object source, int period, double vfactor = 0.7, bool useSma = true) : this(period, vfactor, useSma) public T3(object source, int period, double vfactor = 0.7, bool useSma = true) : this(period, vfactor, useSma) {
{
var pubEvent = source.GetType().GetEvent("Pub"); var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
} }
public override void Init() public override void Init() {
{
base.Init();
_lastEma1 = _lastEma2 = _lastEma3 = _lastEma4 = _lastEma5 = _lastEma6 = 0; _lastEma1 = _lastEma2 = _lastEma3 = _lastEma4 = _lastEma5 = _lastEma6 = 0;
_buffer1.Clear(); _buffer1.Clear();
_buffer2.Clear(); _buffer2.Clear();
@@ -55,10 +49,8 @@ public class T3 : AbstractBase
_buffer6.Clear(); _buffer6.Clear();
} }
protected override void ManageState(bool isNew) protected override void ManageState(bool isNew) {
{ if (isNew) {
if (isNew)
{
_lastValidValue = Input.Value; _lastValidValue = Input.Value;
_index++; _index++;
_p_lastEma1 = _lastEma1; _p_lastEma1 = _lastEma1;
@@ -67,9 +59,7 @@ public class T3 : AbstractBase
_p_lastEma4 = _lastEma4; _p_lastEma4 = _lastEma4;
_p_lastEma5 = _lastEma5; _p_lastEma5 = _lastEma5;
_p_lastEma6 = _lastEma6; _p_lastEma6 = _lastEma6;
} } else {
else
{
_lastEma1 = _p_lastEma1; _lastEma1 = _p_lastEma1;
_lastEma2 = _p_lastEma2; _lastEma2 = _p_lastEma2;
_lastEma3 = _p_lastEma3; _lastEma3 = _p_lastEma3;
@@ -80,18 +70,14 @@ public class T3 : AbstractBase
} }
protected override double Calculation() protected override double Calculation() {
{
ManageState(Input.IsNew); ManageState(Input.IsNew);
double ema1, ema2, ema3, ema4, ema5, ema6; double ema1, ema2, ema3, ema4, ema5, ema6;
if (_index == 1) if (_index == 1) {
{
ema1 = ema2 = ema3 = ema4 = ema5 = ema6 = Input.Value; ema1 = ema2 = ema3 = ema4 = ema5 = ema6 = Input.Value;
} } else if (_index <= _period && _useSma) {
else if (_index <= _period && _useSma)
{
_buffer1.Add(Input.Value, Input.IsNew); _buffer1.Add(Input.Value, Input.IsNew);
ema1 = _buffer1.Average(); ema1 = _buffer1.Average();
_buffer2.Add(ema1, Input.IsNew); _buffer2.Add(ema1, Input.IsNew);
@@ -104,9 +90,7 @@ public class T3 : AbstractBase
ema5 = _buffer5.Average(); ema5 = _buffer5.Average();
_buffer6.Add(ema5, Input.IsNew); _buffer6.Add(ema5, Input.IsNew);
ema6 = _buffer6.Average(); ema6 = _buffer6.Average();
} } else {
else
{
ema1 = _k * (Input.Value - _lastEma1) + _lastEma1; ema1 = _k * (Input.Value - _lastEma1) + _lastEma1;
ema2 = _k * (ema1 - _lastEma2) + _lastEma2; ema2 = _k * (ema1 - _lastEma2) + _lastEma2;
ema3 = _k * (ema2 - _lastEma3) + _lastEma3; ema3 = _k * (ema2 - _lastEma3) + _lastEma3;
+71
View File
@@ -0,0 +1,71 @@
namespace QuanTAlib;
/// <summary>
/// Provides a base implementation for financial indicators in the QuanTAlib library.
/// This abstract class implements the iTValue interface and defines common properties
/// and methods used by inheriting indicator types.
/// </summary>
public abstract class AbstractBarBase : iTValue
{
public DateTime Time { get; set; }
public double Value { get; set; }
public bool IsNew { get; set; }
public bool IsHot { get; set; }
public TBar Input { get; set; }
public String Name { get; set; } = "";
public int WarmupPeriod { 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 AbstractBarBase()
{ //add parameters into constructor
}
public void Sub(object source, in TBarEventArgs args) => Calc(args.Bar);
public virtual void Init()
{
_index = 0;
_lastValidValue = 0;
}
public virtual TValue Calc(TBar input)
{
Input = input;
if (double.IsNaN(input.Close) || double.IsInfinity(input.Close))
{
return Process(new TValue(Time: input.Time, Value: GetLastValid(), IsNew: input.IsNew, IsHot: true));
}
this.Value = Calculation();
return Process(new TValue(Time: Input.Time, Value: this.Value, IsNew: Input.IsNew, IsHot: this.IsHot));
}
protected virtual double GetLastValid()
{
return this.Value;
}
protected abstract void ManageState(bool isNew);
protected abstract double Calculation();
/// <summary>
/// Processes the calculated value, updates the indicator's own state,
/// and publishes the result through an event.
/// </summary>
/// <param name="value">The calculated TValue to process.</param>
/// <returns>The processed TValue.</returns>
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;
}
}
+2 -1
View File
@@ -84,7 +84,8 @@ public class TBarSeries : List<TBar>
public new virtual void Add(TBar bar) public new virtual void Add(TBar bar)
{ {
if (bar.IsNew) { base.Add(bar); } else { this[^1] = bar; } if (bar.IsNew || base.Count == 0) { base.Add(bar); }
else { this[^1] = bar; }
Pub?.Invoke(this, new TBarEventArgs(bar)); Pub?.Invoke(this, new TBarEventArgs(bar));
Open.Add(bar.Time, bar.Open, IsNew: bar.IsNew, IsHot: true); Open.Add(bar.Time, bar.Open, IsNew: bar.IsNew, IsHot: true);
+1 -1
View File
@@ -60,7 +60,7 @@ public class TSeries : List<TValue>
public new virtual void Add(TValue tick) public new virtual void Add(TValue tick)
{ {
if (tick.IsNew) { base.Add(tick); } if (tick.IsNew || base.Count==0) { base.Add(tick); }
else { this[^1] = tick; } else { this[^1] = tick; }
Pub?.Invoke(this, new ValueEventArgs(tick)); Pub?.Invoke(this, new ValueEventArgs(tick));
} }
-1
View File
@@ -23,7 +23,6 @@
<ItemGroup> <ItemGroup>
<None Include="readme.md" Pack="true" PackagePath=""/> <None Include="readme.md" Pack="true" PackagePath=""/>
<None Include="..\.github\QuanTAlib2.png" Pack="true" Visible="false" PackagePath=""/> <None Include="..\.github\QuanTAlib2.png" Pack="true" Visible="false" PackagePath=""/>
<PackageReference Include="Microsoft.DotNet.Interactive.Formatting" Version="1.0.0-beta.24229.4" />
<PackageReference Include="System.Text.Json" Version="9.0.0-rc.1.24431.7" /> <PackageReference Include="System.Text.Json" Version="9.0.0-rc.1.24431.7" />
</ItemGroup> </ItemGroup>
+71
View File
@@ -0,0 +1,71 @@
namespace QuanTAlib;
public class Atr : AbstractBarBase
{
private readonly int _period;
private readonly Ema _ma;
private double _prevClose, _p_prevClose;
public Atr(int period) : base()
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
_period = period;
_ma = new(1.0/period);
WarmupPeriod = _ma.WarmupPeriod;
Name = $"ATR({_period})";
}
public Atr(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
}
public override void Init()
{
base.Init();
_ma.Init();
_prevClose = double.NaN;
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_index++;
_p_prevClose = _prevClose;
}
else
{
_prevClose = _p_prevClose;
}
}
protected override double Calculation()
{
ManageState(Input.IsNew);
double trueRange = Math.Max(
Math.Max(
Input.High - Input.Low,
Math.Abs(Input.High - _prevClose)
),
Math.Abs(Input.Low - _prevClose)
);
if (_index < 2)
{
trueRange = Input.High - Input.Low;
}
TValue emaTrueRange = _ma.Calc(new TValue(Input.Time, trueRange, Input.IsNew));
IsHot = _ma.IsHot;
_prevClose = Input.Close;
return emaTrueRange.Value;
}
}
+45
View File
@@ -0,0 +1,45 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#r "nuget:Skender.Stock.Indicators"
#r "..\lib\obj\Debug\QuanTAlib.dll"
#!csharp
using Skender.Stock.Indicators;
using QuanTAlib;
GbmFeed gbm = new();
Atr atr = new(gbm, 5);
TSeries res = new(atr);
gbm.Add(100);
IEnumerable<Quote> quotes = gbm.Select(item => new Quote { Date = item.Time, Open = (decimal)item.Open,
High = (decimal)item.High, Low = (decimal)item.Low, Close = (decimal)item.Close, Volume = (decimal)item.Volume });
var SkResults = quotes.GetAtr(5).Select(i => i.Atr.Null2NaN()!);
for (int i=0; i< gbm.Length; i++) {
Console.WriteLine($"{gbm.High[i].Value,6:F2} {gbm.Low[i].Value,6:F2} {gbm.Close[i].Value,6:F2}\t\t{res[i].Value,10:F4} {SkResults.ElementAt(i),10:F4}");
}
#!csharp
Random rnd = new((int)DateTime.Now.Ticks);
GbmFeed feed = new(sigma: 0.5, mu: 0.0);
TBarSeries bars = new(feed);
feed.Add(20);
IEnumerable<Quote> quotes;
int period = rnd.Next(5) + 2;
Atr ma = new(period: period);
TSeries QL = new();
foreach (TBar item in bars) {
Console.WriteLine($"{ma.Calc(item)}");
//QL.Add(ma.Calc(item));
}
#!csharp
bars
-25
View File
@@ -1,25 +0,0 @@
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class AmaIndicator : IndicatorBase
{
[InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)]
public int Period { get; set; } = 10;
[InputParameter("Alpha", sortIndex: 2, minimum: -0.01, maximum: 1.0, increment: 0.01, decimalPlaces: 2)]
public double Alpha { get; set; } = 0.1;
private Ama? ma;
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"AMA {Period} : {Alpha} : {SourceName}";
public AmaIndicator()
{
Name = "AMA - Adaptive Moving Average";
}
protected override void InitIndicator()
{
ma = new Ama(period: Period, alpha: Alpha);
}
}
-1
View File
@@ -8,7 +8,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="8.0.0" /> <PackageReference Include="System.Drawing.Common" Version="8.0.0" />
<PackageReference Include="Microsoft.DotNet.Interactive.Formatting" Version="1.0.0-beta.21459.1" />
<Compile Include="..\..\lib\**\*.cs" Exclude="..\..\lib\obj\**"> <Compile Include="..\..\lib\**\*.cs" Exclude="..\..\lib\obj\**">
<Link>lib\%(RecursiveDir)%(Filename)%(Extension)</Link> <Link>lib\%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile> </Compile>
-1
View File
@@ -8,7 +8,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="8.0.0" /> <PackageReference Include="System.Drawing.Common" Version="8.0.0" />
<PackageReference Include="Microsoft.DotNet.Interactive.Formatting" Version="1.0.0-beta.21459.1" />
<Compile Include="..\..\lib\**\*.cs" Exclude="..\..\lib\obj\**"> <Compile Include="..\..\lib\**\*.cs" Exclude="..\..\lib\obj\**">
<Link>lib\%(RecursiveDir)%(Filename)%(Extension)</Link> <Link>lib\%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile> </Compile>
+136
View File
@@ -0,0 +1,136 @@
using System.Drawing;
using TradingPlatform.BusinessLayer;
using TradingPlatform.BusinessLayer.Chart;
using System.Runtime.CompilerServices;
using System.Drawing.Drawing2D;
using System.Collections;
using TradingPlatform.BusinessLayer.TimeSync;
namespace QuanTAlib;
#pragma warning disable CA1416 // Validate platform compatibility
public abstract class IndicatorBarBase : Indicator, IWatchlistIndicator
{
[InputParameter("Show cold values", sortIndex: 20)]
public bool ShowColdValues { get; set; } = true;
public int MinHistoryDepths { get; set; }
// LineSeries.LineSeries(string, Color, int, LineStyle)'
protected LineSeries? Series;
protected abstract AbstractBarBase QuanTAlib { get; }
int IWatchlistIndicator.MinHistoryDepths => 0;
protected IndicatorBarBase()
{
OnBackGround = true;
SeparateWindow = false;
Series = new(name: $"{Name}", color: Color.RoyalBlue, width: 2, style: LineStyle.Solid);
AddLineSeries(Series);
}
protected abstract void InitIndicator();
protected override void OnInit()
{
InitIndicator();
base.OnInit();
}
protected override void OnUpdate(UpdateArgs args)
{
TBar bar = new(Time: Time(),
Open: GetPrice(PriceType.Open),
High: GetPrice(PriceType.High),
Low: GetPrice(PriceType.Low),
Close: GetPrice(PriceType.Close),
Volume: GetPrice(PriceType.Volume),
IsNew: args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar);
TValue result = QuanTAlib.Calc(bar);
Series!.SetValue(result.Value);
Series!.SetMarker(0, Color.Transparent);
}
public override void OnPaintChart(PaintChartEventArgs args)
{
base.OnPaintChart(args);
List<Point> allPoints = new List<Point>();
if (CurrentChart == null) { return; }
Graphics gr = args.Graphics;
var mainWindow = this.CurrentChart.Windows[args.WindowIndex];
var converter = mainWindow.CoordinatesConverter;
var clientRect = mainWindow.ClientRectangle;
gr.SetClip(clientRect);
DateTime leftTime = new[] { converter.GetTime(clientRect.Left), Time(this.Count - 1) }.Max();
DateTime rightTime = new[] { converter.GetTime(clientRect.Right), Time(0) }.Min();
int leftIndex = (int)HistoricalData.GetIndexByTime(leftTime.Ticks) + 1;
int rightIndex = (int)HistoricalData.GetIndexByTime(rightTime.Ticks);
for (int i = rightIndex; i < leftIndex; i++)
{
int barX = (int)converter.GetChartX(Time(i));
int barY = (int)converter.GetChartY(Series![i]);
int halfBarWidth = CurrentChart.BarsWidth / 2;
Point point = new Point(barX + halfBarWidth, barY);
allPoints.Add(point);
}
if (allPoints.Count > 1)
{
DrawSmoothCombinedCurve(gr, allPoints, this.Count - QuanTAlib.WarmupPeriod - rightIndex);
}
}
private void DrawSmoothCombinedCurve(Graphics gr, List<Point> allPoints, int hotCount)
{
if (allPoints.Count < 2) { return; }
using (Pen defaultPen = new(Series!.Color, Series.Width) { DashStyle = ConvertLineStyleToDashStyle(Series.Style) })
using (Pen coldPen = new(Series!.Color, Series.Width) { DashStyle = DashStyle.Dot })
{
// Draw the hot part
if (hotCount > 0)
{
var hotPoints = allPoints.Take(Math.Min(hotCount + 1, allPoints.Count)).ToArray();
gr.DrawCurve(defaultPen, hotPoints, 0, hotPoints.Length - 1, (float)0.1);
}
// Draw the cold part
if (ShowColdValues && hotCount < allPoints.Count)
{
var coldPoints = allPoints.Skip(Math.Max(0, hotCount)).ToArray();
gr.DrawCurve(coldPen, coldPoints, 0, coldPoints.Length - 1, (float)0.1);
}
}
}
private static DashStyle ConvertLineStyleToDashStyle(LineStyle lineStyle)
{
return lineStyle switch
{
LineStyle.Solid => DashStyle.Solid,
LineStyle.Dash => DashStyle.Dash,
LineStyle.Dot => DashStyle.Dot,
LineStyle.DashDot => DashStyle.DashDot,
_ => DashStyle.Solid,
};
}
protected static void DrawText(Graphics gr, string text, Rectangle clientRect)
{
Font font = new Font("Inter", 8);
SizeF textSize = gr.MeasureString(text, font);
RectangleF textRect = new RectangleF(clientRect.Left + 5,
clientRect.Bottom - textSize.Height - 10,
textSize.Width + 10, textSize.Height + 10);
gr.FillRectangle(SystemBrushes.ControlDarkDark, textRect);
gr.DrawString(text, font, Brushes.White, new PointF(textRect.X + 6, textRect.Y + 5));
}
}
+23
View File
@@ -0,0 +1,23 @@
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class AtrIndicator : IndicatorBarBase
{
[InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
public int Period { get; set; } = 20;
private Atr? atr;
protected override AbstractBarBase QuanTAlib => atr!;
public override string ShortName => $"ATR {Period}";
public AtrIndicator()
{
Name = "ATR - Average True Range";
SeparateWindow = true;
}
protected override void InitIndicator()
{
atr = new(Period);
MinHistoryDepths = atr!.WarmupPeriod;
}
}
+29
View File
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AlgoType>Indicator</AlgoType>
<OutputPath>bin\$(Configuration)\</OutputPath>
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
<UpdateAssemblyInfo>true</UpdateAssemblyInfo>
<GenerateGitVersionInformation>true</GenerateGitVersionInformation>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
<Compile Include="..\..\lib\**\*.cs" Exclude="..\..\lib\obj\**">
<Link>lib\%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
<Target Name="CopyCustomContent" AfterTargets="AfterBuild" Condition="'$(IsLocalBuild)' == 'true'">
<Copy SourceFiles="$(OutputPath)\Volatility.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Volatility" />
</Target>
<ItemGroup>
<Reference Include="TradingPlatform.BusinessLayer">
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
</Reference>
<None Include="..\..\.github\TradingPlatform.BusinessLayer.xml">
<Link>TradingPlatform.BusinessLayer.xml</Link>
</None>
</ItemGroup>
</Project>
+136
View File
@@ -0,0 +1,136 @@
using System.Drawing;
using TradingPlatform.BusinessLayer;
using TradingPlatform.BusinessLayer.Chart;
using System.Runtime.CompilerServices;
using System.Drawing.Drawing2D;
using System.Collections;
using TradingPlatform.BusinessLayer.TimeSync;
namespace QuanTAlib;
#pragma warning disable CA1416 // Validate platform compatibility
public abstract class IndicatorBarBase : Indicator, IWatchlistIndicator
{
[InputParameter("Show cold values", sortIndex: 20)]
public bool ShowColdValues { get; set; } = true;
public int MinHistoryDepths { get; set; }
// LineSeries.LineSeries(string, Color, int, LineStyle)'
protected LineSeries? Series;
protected abstract AbstractBarBase QuanTAlib { get; }
int IWatchlistIndicator.MinHistoryDepths => 0;
protected IndicatorBarBase()
{
OnBackGround = true;
SeparateWindow = false;
Series = new(name: $"{Name}", color: Color.RoyalBlue, width: 2, style: LineStyle.Solid);
AddLineSeries(Series);
}
protected abstract void InitIndicator();
protected override void OnInit()
{
InitIndicator();
base.OnInit();
}
protected override void OnUpdate(UpdateArgs args)
{
TBar bar = new(Time: Time(),
Open: GetPrice(PriceType.Open),
High: GetPrice(PriceType.High),
Low: GetPrice(PriceType.Low),
Close: GetPrice(PriceType.Close),
Volume: GetPrice(PriceType.Volume),
IsNew: args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar);
TValue result = QuanTAlib.Calc(bar);
Series!.SetValue(result.Value);
Series!.SetMarker(0, Color.Transparent);
}
public override void OnPaintChart(PaintChartEventArgs args)
{
base.OnPaintChart(args);
List<Point> allPoints = new List<Point>();
if (CurrentChart == null) { return; }
Graphics gr = args.Graphics;
var mainWindow = this.CurrentChart.Windows[args.WindowIndex];
var converter = mainWindow.CoordinatesConverter;
var clientRect = mainWindow.ClientRectangle;
gr.SetClip(clientRect);
DateTime leftTime = new[] { converter.GetTime(clientRect.Left), Time(this.Count - 1) }.Max();
DateTime rightTime = new[] { converter.GetTime(clientRect.Right), Time(0) }.Min();
int leftIndex = (int)HistoricalData.GetIndexByTime(leftTime.Ticks) + 1;
int rightIndex = (int)HistoricalData.GetIndexByTime(rightTime.Ticks);
for (int i = rightIndex; i < leftIndex; i++)
{
int barX = (int)converter.GetChartX(Time(i));
int barY = (int)converter.GetChartY(Series![i]);
int halfBarWidth = CurrentChart.BarsWidth / 2;
Point point = new Point(barX + halfBarWidth, barY);
allPoints.Add(point);
}
if (allPoints.Count > 1)
{
DrawSmoothCombinedCurve(gr, allPoints, this.Count - QuanTAlib.WarmupPeriod - rightIndex);
}
}
private void DrawSmoothCombinedCurve(Graphics gr, List<Point> allPoints, int hotCount)
{
if (allPoints.Count < 2) { return; }
using (Pen defaultPen = new(Series!.Color, Series.Width) { DashStyle = ConvertLineStyleToDashStyle(Series.Style) })
using (Pen coldPen = new(Series!.Color, Series.Width) { DashStyle = DashStyle.Dot })
{
// Draw the hot part
if (hotCount > 0)
{
var hotPoints = allPoints.Take(Math.Min(hotCount + 1, allPoints.Count)).ToArray();
gr.DrawCurve(defaultPen, hotPoints, 0, hotPoints.Length - 1, (float)0.1);
}
// Draw the cold part
if (ShowColdValues && hotCount < allPoints.Count)
{
var coldPoints = allPoints.Skip(Math.Max(0, hotCount)).ToArray();
gr.DrawCurve(coldPen, coldPoints, 0, coldPoints.Length - 1, (float)0.1);
}
}
}
private static DashStyle ConvertLineStyleToDashStyle(LineStyle lineStyle)
{
return lineStyle switch
{
LineStyle.Solid => DashStyle.Solid,
LineStyle.Dash => DashStyle.Dash,
LineStyle.Dot => DashStyle.Dot,
LineStyle.DashDot => DashStyle.DashDot,
_ => DashStyle.Solid,
};
}
protected static void DrawText(Graphics gr, string text, Rectangle clientRect)
{
Font font = new Font("Inter", 8);
SizeF textSize = gr.MeasureString(text, font);
RectangleF textRect = new RectangleF(clientRect.Left + 5,
clientRect.Bottom - textSize.Height - 10,
textSize.Width + 10, textSize.Height + 10);
gr.FillRectangle(SystemBrushes.ControlDarkDark, textRect);
gr.DrawString(text, font, Brushes.White, new PointF(textRect.X + 6, textRect.Y + 5));
}
}