init
This commit is contained in:
commit
831e17c68b
404
.gitignore
vendored
Normal file
404
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,404 @@
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
# but not Directory.Build.rsp, as it configures directory-level build defaults
|
||||||
|
!Directory.Build.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.tlog
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||||
|
*.vbp
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||||
|
*.dsw
|
||||||
|
*.dsp
|
||||||
|
|
||||||
|
# Visual Studio 6 technical files
|
||||||
|
*.ncb
|
||||||
|
*.aps
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# Visual Studio History (VSHistory) files
|
||||||
|
.vshistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# VS Code files for those working on multiple tools
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
*.png
|
||||||
|
|
||||||
|
Secrets.cs
|
||||||
26
.vscode/launch.json
vendored
Normal file
26
.vscode/launch.json
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||||
|
// Use hover for the description of the existing attributes
|
||||||
|
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||||
|
"name": ".NET Core Launch (console)",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
// If you have changed target frameworks, make sure to update the program path.
|
||||||
|
"program": "${workspaceFolder}/bin/Debug/net7.0/SignalsTestCmd.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||||
|
"console": "internalConsole",
|
||||||
|
"stopAtEntry": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ".NET Core Attach",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "attach"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
41
.vscode/tasks.json
vendored
Normal file
41
.vscode/tasks.json
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/SignalsTestCmd.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/SignalsTestCmd.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/SignalsTestCmd.csproj"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
24
Brian.cs
Normal file
24
Brian.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
using BinanceExchange.API.Client;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SignalsTest
|
||||||
|
{
|
||||||
|
public class Brian
|
||||||
|
{
|
||||||
|
private static BinanceClient m_client;
|
||||||
|
|
||||||
|
public static BinanceClient Client { get { if(m_client == null)
|
||||||
|
{
|
||||||
|
m_client = new BinanceClient(new ClientConfiguration()
|
||||||
|
{
|
||||||
|
ApiKey = Secrets.BINANCE_API_PK,
|
||||||
|
SecretKey = Secrets.BINANCE_API_SK,
|
||||||
|
});
|
||||||
|
} return m_client;
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
157
CoinWatch.cs
Normal file
157
CoinWatch.cs
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
using BinanceExchange.API.Client;
|
||||||
|
using BinanceExchange.API.Enums;
|
||||||
|
using BinanceExchange.API.Models.Request;
|
||||||
|
using BinanceExchange.API.Models.Response;
|
||||||
|
using BinanceExchange.API.Models.WebSocket;
|
||||||
|
using BinanceExchange.API.Websockets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||||
|
|
||||||
|
namespace SignalsTest
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public class CoinWatch
|
||||||
|
{
|
||||||
|
public bool kickstarted = false;
|
||||||
|
public string pair;
|
||||||
|
public int index;
|
||||||
|
public KlineInterval interval = KlineInterval.FifteenMinutes;
|
||||||
|
public List<KlineCandleStickResponse> candles=new List<KlineCandleStickResponse>();
|
||||||
|
public List<TAReport> reports = new List<TAReport>();
|
||||||
|
public event EventHandler<BinanceTradeData> PriceUpdated;
|
||||||
|
bool usingCache;
|
||||||
|
public CoinWatch(string pair,int index, KlineInterval _interval = KlineInterval.FifteenMinutes , bool useCache=false)
|
||||||
|
{
|
||||||
|
this.pair = pair;
|
||||||
|
this.index = index;
|
||||||
|
interval = _interval;
|
||||||
|
usingCache = useCache;
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Init()
|
||||||
|
{
|
||||||
|
if(usingCache){
|
||||||
|
if(File.Exists(AppDomain.CurrentDomain.BaseDirectory+"/"+pair+".txt")){
|
||||||
|
try{
|
||||||
|
|
||||||
|
}catch{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InitLivestream();
|
||||||
|
KeepUpdatingCandles();
|
||||||
|
// TestCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
async void TestCallbacks()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
|
PriceUpdated?.Invoke(this, new BinanceTradeData() { BestAskPrice=0 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task UpdateCandles()
|
||||||
|
{
|
||||||
|
GetKlinesCandlesticksRequest req = new GetKlinesCandlesticksRequest();
|
||||||
|
req.Interval = interval;
|
||||||
|
req.Symbol = pair;
|
||||||
|
req.EndTime = DateTime.Now;
|
||||||
|
req.Limit = 100;
|
||||||
|
|
||||||
|
candles = await Brian.Client.GetKlinesCandlesticks(req);
|
||||||
|
Console.WriteLine($"Done gettings Kandles for {req.Symbol}, {candles.Count} kandles retreived");
|
||||||
|
kickstarted = true;
|
||||||
|
Analyze(req.Symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
async void Analyze(string symbol){
|
||||||
|
int[] mas = new int[] { 7, 12, 25 };
|
||||||
|
reports = new List<TAReport>();
|
||||||
|
decimal max = 0;
|
||||||
|
decimal min = 100000000;
|
||||||
|
decimal maxVol = 0;
|
||||||
|
|
||||||
|
|
||||||
|
for(int i=0; i < candles.Count; i++){
|
||||||
|
|
||||||
|
TAReport report = TAReport.Generate(pair, Utils.GetMinutesForInterval(interval) ,candles, i,reports);
|
||||||
|
if(candles[i].Close > max){
|
||||||
|
max = candles[i].Close;
|
||||||
|
}
|
||||||
|
if(candles[i].Close < min){
|
||||||
|
min = candles[i].Close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(candles[i].Volume > maxVol){
|
||||||
|
maxVol = candles[i].Volume;
|
||||||
|
}
|
||||||
|
reports.Add(report);
|
||||||
|
|
||||||
|
}
|
||||||
|
Console.WriteLine($"Drawing chart for {reports.Count} candles, Coin: {symbol}, ceil:{max}, floor:{min}");
|
||||||
|
|
||||||
|
// Console.WriteLine("Picasso did his job");
|
||||||
|
// Console.WriteLine(reports[reports.Count-1].toJson());
|
||||||
|
bool isStSwitch=false;
|
||||||
|
|
||||||
|
for(int i=0; i< 2; i++){
|
||||||
|
bool _isStSwitch = reports[reports.Count-1-i].STUp != reports[reports.Count-i-2].STUp;
|
||||||
|
|
||||||
|
if(_isStSwitch){
|
||||||
|
isStSwitch=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string triggers = "";
|
||||||
|
|
||||||
|
if(isStSwitch){
|
||||||
|
triggers += "Switched SuperTrend\n";
|
||||||
|
}
|
||||||
|
if(reports[reports.Count-1].TGOR && !reports[reports.Count-2].TGOR){//Ignore if two in row
|
||||||
|
triggers += "Price dropped\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(triggers!= ""){
|
||||||
|
Picasso.DrawChart(reports, max ,min, maxVol, symbol);
|
||||||
|
|
||||||
|
string message = $"`{symbol}` {triggers} \nCurrent price: {reports[reports.Count-1].Close}";
|
||||||
|
Messenger.instance.ScheduleMessage(message, symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async void KeepUpdatingCandles()
|
||||||
|
{
|
||||||
|
int delay = (index * 1000);
|
||||||
|
await Task.Delay(delay);
|
||||||
|
|
||||||
|
UpdateCandles();
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
await Task.Delay(60000 + delay);
|
||||||
|
Console.WriteLine($"Loop call, ({index}) , {DateTime.Now.Minute} = {DateTime.Now.Minute % Utils.GetMinutesForInterval(interval)} ");
|
||||||
|
if (DateTime.Now.Minute % Utils.GetMinutesForInterval(interval) == 0) { UpdateCandles(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitLivestream()
|
||||||
|
{
|
||||||
|
var manualWebsocket = new InstanceBinanceWebSocketClient(Brian.Client);
|
||||||
|
var socketId = manualWebsocket.ConnectToIndividualSymbolTickerWebSocket(pair, data =>
|
||||||
|
{
|
||||||
|
if(candles.Count > 0){
|
||||||
|
candles[candles.Count - 1].Close = data.BestAskPrice;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
CoinsList.cs
Normal file
37
CoinsList.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
public static class CoinsList{
|
||||||
|
public static List<string> symbols= [
|
||||||
|
"BTCUSDT",
|
||||||
|
"ADAUSDT",
|
||||||
|
"XRPUSDT",
|
||||||
|
"XLMUSDT",
|
||||||
|
"SOLUSDT",
|
||||||
|
"AVAXUSDT",
|
||||||
|
"ENAUSDT",
|
||||||
|
"HIVEUSDT",
|
||||||
|
"STEEMUSDT",
|
||||||
|
"MOVEUSDT",
|
||||||
|
"DOGEUSDT",
|
||||||
|
"PEPEUSDT",
|
||||||
|
"RLCUSDT",
|
||||||
|
"ACTUSDT",
|
||||||
|
"STGUSDT",
|
||||||
|
"ONEUSDT",
|
||||||
|
"LINKUSDT",
|
||||||
|
"ARUSDT",
|
||||||
|
"RUNEUSDT",
|
||||||
|
"USUALUSDT",
|
||||||
|
"ZKUSDT",
|
||||||
|
"JUPUSDT",
|
||||||
|
"LUNAUSDT",
|
||||||
|
"DUSKUSDT",
|
||||||
|
"SUIUSDT",
|
||||||
|
"INJUSDT",
|
||||||
|
"FILUSDT",
|
||||||
|
"GRTUSDT",
|
||||||
|
"HBARUSDT",
|
||||||
|
"CFXUSDT",
|
||||||
|
"TLMUSDT",
|
||||||
|
"NEARUSDT",
|
||||||
|
"FORTHUSDT"
|
||||||
|
];
|
||||||
|
}
|
||||||
169
Indicators.cs
Normal file
169
Indicators.cs
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
using BinanceExchange.API.Models.Response;
|
||||||
|
|
||||||
|
public static class Indicators
|
||||||
|
{
|
||||||
|
|
||||||
|
public static decimal getSMA(List<KlineCandleStickResponse> responses, int curIndex, int interval, int startIndex = 0)
|
||||||
|
{
|
||||||
|
// curIndex = Math.Clamp(curIndex,0, responses.Count);
|
||||||
|
// decimal total = 0;
|
||||||
|
// for(int i=curIndex-interval; i < curIndex; i++){
|
||||||
|
// total += responses[i].Close;
|
||||||
|
// }
|
||||||
|
// // decimal length = (curIndex-startIndex); if(length <= 0){length=1;}
|
||||||
|
// // decimal N = (length / (decimal)interval);
|
||||||
|
// Console.WriteLine($"SMA Cacl ({interval}) : {total}/{interval} = {total/interval}");
|
||||||
|
|
||||||
|
// return total / interval;
|
||||||
|
|
||||||
|
decimal total = 0;
|
||||||
|
for (int x = (curIndex > 1500) ? 1500 : 0; x < interval; x++)
|
||||||
|
{
|
||||||
|
total += (curIndex - x >= 0) ? responses[curIndex - x].Close : (decimal)0;
|
||||||
|
}
|
||||||
|
return total / (decimal)interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static decimal getSMA(List<decimal> responses, int curIndex, int interval, int startIndex = 0)
|
||||||
|
{
|
||||||
|
decimal total = 0;
|
||||||
|
for (int x = (curIndex > 1500) ? 1500 : 0; x < interval; x++)
|
||||||
|
{
|
||||||
|
total += (curIndex - x >= 0) ? responses[curIndex - x] : (decimal)0;
|
||||||
|
}
|
||||||
|
return total / (decimal)interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static decimal getEMA(List<KlineCandleStickResponse> responses, int curIndex, int startIndex, int periods, decimal? prevEma = null)
|
||||||
|
{
|
||||||
|
if (curIndex < 1) { return 0; }
|
||||||
|
if (startIndex - curIndex > 1500) { return 0; }; if (curIndex >= responses.Count) { return 0; };
|
||||||
|
|
||||||
|
|
||||||
|
// decimal N = (decimal)curIndex / (decimal)periods;
|
||||||
|
|
||||||
|
decimal multiplier = (decimal)2 / ((decimal)(periods + 1));
|
||||||
|
decimal firstHalf = responses[curIndex].Close * multiplier; //First half of the equation
|
||||||
|
decimal secondHalf = getEMA(responses, curIndex - 1, startIndex, periods) * (1 - multiplier); //Second half of the equation
|
||||||
|
// decimal secondHalf = (prevEma ?? getSMA(responses, curIndex-1, periods)) * (1- multiplier); //Second half of the equation
|
||||||
|
|
||||||
|
return firstHalf + secondHalf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static decimal getEMA(List<decimal> responses, int curIndex, int startIndex, int periods)
|
||||||
|
{
|
||||||
|
if (curIndex < 1) { return 0; }
|
||||||
|
if (startIndex - curIndex > 1500) { return 0; };
|
||||||
|
if (curIndex >= responses.Count) { return 0; };
|
||||||
|
|
||||||
|
// decimal N = (decimal)curIndex / (decimal)periods;
|
||||||
|
|
||||||
|
decimal multiplier = (decimal)2 / ((decimal)(periods + 1));
|
||||||
|
|
||||||
|
decimal firstHalf = responses[curIndex] * multiplier; //First half of the equation
|
||||||
|
decimal secondHalf = getEMA(responses, curIndex - 1, startIndex, periods) * (1 - multiplier); //Second half of the equation
|
||||||
|
// decimal secondHalf = (prevEma ?? getSMA(responses, curIndex-1, periods)) * (1- multiplier); //Second half of the equation
|
||||||
|
|
||||||
|
return firstHalf + secondHalf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static decimal getMACD(List<KlineCandleStickResponse> responses, int shortPeriod, int longPeriod, int curIndex)
|
||||||
|
{
|
||||||
|
return getEMA(responses, curIndex, curIndex, shortPeriod) - getEMA(responses, curIndex, curIndex, longPeriod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static decimal getATR(List<KlineCandleStickResponse> responses, int period, int curIndex, List<decimal> prevATRs)
|
||||||
|
{
|
||||||
|
if (curIndex <= 0 || curIndex > responses.Count) { return 0; }
|
||||||
|
|
||||||
|
if (curIndex >= responses.Count) { return 0; };
|
||||||
|
|
||||||
|
decimal TR = responses[curIndex].High - responses[curIndex].Low;
|
||||||
|
if (curIndex > 1)
|
||||||
|
{
|
||||||
|
decimal tr2 = responses[curIndex].High - responses[curIndex - 1].Close;
|
||||||
|
decimal tr3 = responses[curIndex].Low - responses[curIndex - 1].Close;
|
||||||
|
if (tr2 > TR)
|
||||||
|
{
|
||||||
|
TR = tr2;
|
||||||
|
}
|
||||||
|
if (tr3 > TR)
|
||||||
|
{
|
||||||
|
TR = tr3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curIndex < period)
|
||||||
|
{
|
||||||
|
//get just the TR
|
||||||
|
return TR;
|
||||||
|
}
|
||||||
|
decimal prevATR = 0;
|
||||||
|
if (prevATRs.Count > 0)
|
||||||
|
{
|
||||||
|
// int start = curIndex - period;
|
||||||
|
// for (int i = start; i < curIndex; i++)
|
||||||
|
// {
|
||||||
|
// prevATR += prevATRs[i];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// prevATR = (prevATR) / (decimal)(curIndex-start);
|
||||||
|
prevATR = prevATRs[curIndex - 1];
|
||||||
|
}
|
||||||
|
decimal ATR = (decimal)((prevATR * (decimal)(period - 1)) + TR) / (decimal)period;
|
||||||
|
return ATR;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static decimal getRSI(List<KlineCandleStickResponse> responses, int index, int period = 14){
|
||||||
|
decimal avgGain = 0;
|
||||||
|
decimal avgLoss =0;
|
||||||
|
if(index < 2){return 0;}
|
||||||
|
int length = 0;
|
||||||
|
for(int i=index; i > index - period && i > 0; i--){
|
||||||
|
length++;
|
||||||
|
avgGain += responses[i].Close - responses[i-1].Close;
|
||||||
|
avgLoss += responses[i-1].Close - responses[i].Close;
|
||||||
|
}
|
||||||
|
if(length <=0){return 0;}
|
||||||
|
avgGain /= length;
|
||||||
|
avgLoss /= length;
|
||||||
|
|
||||||
|
decimal f =(1.0m+(avgGain/(avgLoss==0 ? 1: avgLoss))); //Avoiding dividing by 0
|
||||||
|
if(f<=0){return 0;}
|
||||||
|
return 100.0m - (100.0m/f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool didMACDLineCrossSignalLine(decimal[] MACDs, decimal[] Signals, int index, int period = 7, decimal threshold = (decimal)0.1)
|
||||||
|
{
|
||||||
|
int counter = 0;
|
||||||
|
if (index >= MACDs.Length || index >= Signals.Length) { return false; }
|
||||||
|
if (index - period < 0) { return false; };
|
||||||
|
for (int i = index; i > index - period; i--)
|
||||||
|
{
|
||||||
|
if (MACDs[i] < Signals[i])
|
||||||
|
{
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool wasMACDUnder = counter > ((float)period / 2f);
|
||||||
|
return wasMACDUnder && MACDs[index] > Signals[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static decimal getAvgDiff(List<KlineCandleStickResponse> responses, int i)
|
||||||
|
{
|
||||||
|
decimal avgDiff = 0;
|
||||||
|
|
||||||
|
if (i > 10)
|
||||||
|
{
|
||||||
|
for (int k = 1; k < 6; k++)
|
||||||
|
{
|
||||||
|
avgDiff += responses[i - k].Close;
|
||||||
|
}
|
||||||
|
|
||||||
|
avgDiff = avgDiff / (decimal)5;
|
||||||
|
avgDiff = responses[i].Close - avgDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return avgDiff;
|
||||||
|
}
|
||||||
|
}
|
||||||
75
Messenger.cs
Normal file
75
Messenger.cs
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Telegram.Bot;
|
||||||
|
using Telegram.Bot.Exceptions;
|
||||||
|
using Telegram.Bot.Polling;
|
||||||
|
using Telegram.Bot.Types;
|
||||||
|
using Telegram.Bot.Types.Enums;
|
||||||
|
namespace SignalsTest
|
||||||
|
{
|
||||||
|
public class Messenger
|
||||||
|
{
|
||||||
|
|
||||||
|
TelegramBotClient botClient;
|
||||||
|
|
||||||
|
private static Messenger m_instance;
|
||||||
|
public static Messenger instance { get { if (m_instance == null) { m_instance = new Messenger(); } return m_instance; } }
|
||||||
|
|
||||||
|
public const string chatId = "@doralockscryptosignals";
|
||||||
|
public const string chatId_test = "@SignalTestPrivate";
|
||||||
|
|
||||||
|
public Dictionary<string,string> messagesSchedule = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
public void ScheduleMessage(string text, string filename=""){
|
||||||
|
messagesSchedule.Add(text,filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void InitializeScheduler(){
|
||||||
|
string _chatId = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? chatId_test : chatId;
|
||||||
|
|
||||||
|
while(true){
|
||||||
|
await Task.Delay(3500);
|
||||||
|
if(messagesSchedule.Count <=0){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string message = messagesSchedule.Keys.ElementAt(0);
|
||||||
|
string filename = messagesSchedule[message];
|
||||||
|
|
||||||
|
try{
|
||||||
|
if(filename.Length < 2){
|
||||||
|
await botClient.SendTextMessageAsync(_chatId, message);
|
||||||
|
}else{
|
||||||
|
FileStream fsSource = new FileStream($"{filename}.png", FileMode.Open, FileAccess.Read);
|
||||||
|
InputFile photo = InputFile.FromStream(fsSource);
|
||||||
|
await botClient.SendPhotoAsync(_chatId, photo,caption: message);
|
||||||
|
}
|
||||||
|
|
||||||
|
messagesSchedule.Remove(message);
|
||||||
|
}catch(Exception e){
|
||||||
|
Console.WriteLine($"Error occured while sending {message} to {filename}");
|
||||||
|
Console.WriteLine(e.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Messenger()
|
||||||
|
{
|
||||||
|
botClient = new TelegramBotClient(Secrets.TELEGRAM_BOT_TOKEN);
|
||||||
|
using CancellationTokenSource cts = new();
|
||||||
|
|
||||||
|
// StartReceiving does not block the caller thread. Receiving is done on the ThreadPool.
|
||||||
|
ReceiverOptions receiverOptions = new()
|
||||||
|
{
|
||||||
|
AllowedUpdates = Array.Empty<UpdateType>() // receive all update types except ChatMember related updates
|
||||||
|
};
|
||||||
|
|
||||||
|
InitializeScheduler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
Patterns.cs
Normal file
51
Patterns.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
|
||||||
|
using BinanceExchange.API.Models.Response;
|
||||||
|
|
||||||
|
public static class Patterns{
|
||||||
|
public static bool GetTGOR(List<KlineCandleStickResponse> responses, int curIndex){
|
||||||
|
if(curIndex < 10){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int greenCount =0;
|
||||||
|
|
||||||
|
for(int i=curIndex-4; i <= curIndex; i++){
|
||||||
|
|
||||||
|
if(responses[i].Close < responses[i].Open){
|
||||||
|
if(greenCount > 2){
|
||||||
|
//Red after 3 greens
|
||||||
|
int bullRunFlag = 0;
|
||||||
|
//This is an abomniation
|
||||||
|
if(responses[i-1].Close > responses[i-2].Close){
|
||||||
|
bullRunFlag++;
|
||||||
|
}
|
||||||
|
if(responses[i-2].Close > responses[i-3].Close){
|
||||||
|
bullRunFlag++;
|
||||||
|
}
|
||||||
|
if(responses[i-3].Close > responses[i-4].Close){
|
||||||
|
bullRunFlag++;
|
||||||
|
}
|
||||||
|
if(responses[i-4].Close > responses[i-5].Close){
|
||||||
|
bullRunFlag++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(responses[i-5].Close > responses[i-6].Close){
|
||||||
|
bullRunFlag++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bullRunFlag > 2 && responses[i-1].Close > responses[i-1].Open){//It was a bull run
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
greenCount =0;
|
||||||
|
}else{
|
||||||
|
greenCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
118
Picasso.cs
Normal file
118
Picasso.cs
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
using SignalsTest;
|
||||||
|
using System;
|
||||||
|
using SixLabors.Fonts;
|
||||||
|
using SixLabors.ImageSharp;
|
||||||
|
using SixLabors.ImageSharp.Drawing;
|
||||||
|
using SixLabors.ImageSharp.Drawing.Processing;
|
||||||
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
public class Picasso{
|
||||||
|
public static void DrawChart(List<TAReport> reports, decimal max, decimal min, decimal volMax, string filename="test"){
|
||||||
|
// float height = (float)Math.Ceiling(max - min) * 2f;
|
||||||
|
// float width = ((float)height / 9f) * 16f;
|
||||||
|
decimal heightRange = max-min;
|
||||||
|
float height=1080;
|
||||||
|
float width = 1920;
|
||||||
|
float widthMultiplier = width / (float)reports.Count;
|
||||||
|
float heightMultiplier = (height/ (float)heightRange) * 0.6f;
|
||||||
|
|
||||||
|
float candlesOffset = 0.3f * height;
|
||||||
|
float volumeSize = 0.2f * height;
|
||||||
|
using (Image img = new Image<Rgba32>((int)width + 100, (int)height)){
|
||||||
|
|
||||||
|
//Draw Candles
|
||||||
|
for(int i=0; i < reports.Count; i++){
|
||||||
|
// img.Mutate(ctx=> ctx.DrawLine()))
|
||||||
|
PointF[] points = new PointF[2];
|
||||||
|
|
||||||
|
float openVal1 = (float)(reports[i].candle.Open - min) * heightMultiplier;
|
||||||
|
float closeVal1 = (float)(reports[i].candle.Close - min)* heightMultiplier;
|
||||||
|
points[0] =new PointF(i * widthMultiplier, openVal1 + candlesOffset);
|
||||||
|
points[1] =new PointF(i * widthMultiplier, closeVal1+ candlesOffset);
|
||||||
|
|
||||||
|
PointF[] rangePoints = new PointF[2];
|
||||||
|
|
||||||
|
float highVal = (float)(reports[i].candle.High-min)* heightMultiplier;
|
||||||
|
float lowVal = (float)(reports[i].candle.Low-min)* heightMultiplier;
|
||||||
|
|
||||||
|
rangePoints[0] = new PointF(i * widthMultiplier, highVal+ candlesOffset);
|
||||||
|
rangePoints[1] = new PointF(i * widthMultiplier, lowVal+ candlesOffset);
|
||||||
|
|
||||||
|
PointF[] volumePoints = new PointF[2];
|
||||||
|
volumePoints[0] = new PointF(i * widthMultiplier, 0);
|
||||||
|
volumePoints[1] = new PointF(i * widthMultiplier, ((float)reports[i].candle.Volume / (float)volMax) * volumeSize);
|
||||||
|
|
||||||
|
Color candleColor = reports[i].candle.Close > reports[i].candle.Open ? Color.Green : Color.Red;
|
||||||
|
|
||||||
|
img.Mutate(ctx=> ctx.
|
||||||
|
DrawLine(candleColor, 10, points).
|
||||||
|
DrawLine(candleColor, 3, rangePoints).
|
||||||
|
DrawLine(candleColor, 10, volumePoints)
|
||||||
|
);
|
||||||
|
|
||||||
|
if(reports[i].TGOR){
|
||||||
|
PointF[] tgorPoints = new PointF[2];
|
||||||
|
tgorPoints[0] = new PointF(i * widthMultiplier, lowVal+ candlesOffset);
|
||||||
|
tgorPoints[1] = new PointF(i * widthMultiplier, lowVal- 15+ candlesOffset);
|
||||||
|
img.Mutate(ctx=>ctx.DrawLine(Color.Blue, 15, tgorPoints));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// Console.WriteLine("Getting paths");
|
||||||
|
// object t = GetPropByName(reports[reports.Count- 1], "SMA7");
|
||||||
|
// Console.WriteLine(t);
|
||||||
|
// Console.WriteLine(float.Parse(t.ToString()));
|
||||||
|
|
||||||
|
//Overlay
|
||||||
|
IPath sma7Path = GetPath(reports, "SMA7", widthMultiplier,(float)heightMultiplier, (float)min, candlesOffset);
|
||||||
|
IPath sma25Path = GetPath(reports, "SMA25", widthMultiplier,(float)heightMultiplier, (float)min, candlesOffset);
|
||||||
|
IPath stPath = GetPath(reports, "ST", widthMultiplier,(float)heightMultiplier, (float)min, candlesOffset);
|
||||||
|
|
||||||
|
//NewChart
|
||||||
|
FontFamily fontFamily;
|
||||||
|
float TextFontSize = 64f;
|
||||||
|
string TextFont = "Noto Sans Mono";
|
||||||
|
if (!SystemFonts.TryGet(TextFont, out fontFamily))
|
||||||
|
throw new Exception($"Couldn't find font {TextFont}");
|
||||||
|
|
||||||
|
var font = fontFamily.CreateFont(TextFontSize, FontStyle.Regular);
|
||||||
|
|
||||||
|
img.Mutate(ctx => ctx.Draw(Color.Yellow, 2, sma7Path).
|
||||||
|
Draw(Color.Purple, 2, sma25Path).
|
||||||
|
Draw(Color.Green, 3, stPath).
|
||||||
|
Flip(FlipMode.Vertical).
|
||||||
|
DrawText(filename, font,new Color(Rgba32.ParseHex("#000000FF")), new PointF(10,10)));
|
||||||
|
|
||||||
|
img.Save($"{filename}.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static IPath GetPath(List<TAReport> reports, string propName, float widthMultiplier,float heightMultiplier, float min, float offset =0){
|
||||||
|
PathBuilder builder = new PathBuilder();
|
||||||
|
builder.SetOrigin(new PointF(0,0));
|
||||||
|
for(int i=0; i < reports.Count; i++){
|
||||||
|
float newVal = float.Parse(GetPropByName(reports[i],propName).ToString() ?? "0");
|
||||||
|
// Console.WriteLine( newVal);
|
||||||
|
|
||||||
|
float prevVal = i > 0 ? float.Parse(GetPropByName(reports[i-1],propName).ToString() ?? "0") : 0;
|
||||||
|
// Console.WriteLine( prevVal);
|
||||||
|
float preValY =( prevVal - min) * heightMultiplier ;
|
||||||
|
float newValY=(newVal - min) * heightMultiplier;
|
||||||
|
PointF prevPoint = new PointF((i-1)* widthMultiplier, (preValY) +offset);
|
||||||
|
PointF newPoint = new PointF(i * widthMultiplier, (newValY) + offset);
|
||||||
|
// Console.WriteLine(newValY);
|
||||||
|
builder.AddLine(prevPoint, newPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
static object GetPropByName(TAReport report, string propName){
|
||||||
|
string json = report.toJson();
|
||||||
|
Dictionary<string,string> dic = JsonConvert.DeserializeObject<Dictionary<string,string>>(json) ?? new Dictionary<string, string>();
|
||||||
|
// Console.WriteLine(dic[propName]);
|
||||||
|
return dic[propName];
|
||||||
|
}
|
||||||
|
}
|
||||||
44
Program.cs
Normal file
44
Program.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
using BinanceExchange.API.Models.WebSocket;
|
||||||
|
using SignalsTest;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static ManualResetEvent _quitEvent = new ManualResetEvent(false);
|
||||||
|
|
||||||
|
static List<CoinWatch> watches = new List<CoinWatch>();
|
||||||
|
private static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Initializing Messiah");
|
||||||
|
Messenger.instance.ScheduleMessage("Rebooted bot");
|
||||||
|
for (int i=0; i < CoinsList.symbols.Count; i++){
|
||||||
|
CoinWatch btcWatch = new CoinWatch(CoinsList.symbols[i], i);
|
||||||
|
btcWatch.PriceUpdated += CoinWatch_OnPriceUpdate;
|
||||||
|
|
||||||
|
watches.Add(btcWatch);
|
||||||
|
}
|
||||||
|
CheckSuccess();
|
||||||
|
_quitEvent.WaitOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async static void CheckSuccess(){
|
||||||
|
await Task.Delay(120000);
|
||||||
|
|
||||||
|
List<string> failedList = new List<string>();
|
||||||
|
string commasList = "";
|
||||||
|
foreach(CoinWatch coin in watches){
|
||||||
|
if(!coin.kickstarted){
|
||||||
|
failedList.Add(coin.pair);
|
||||||
|
commasList += coin.pair + ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string msg = $"{failedList.Count} Failed out of {watches.Count}. Failed list: \n{commasList}";
|
||||||
|
Console.WriteLine(msg);
|
||||||
|
Messenger.instance.ScheduleMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CoinWatch_OnPriceUpdate(Object? sender,BinanceTradeData data)
|
||||||
|
{
|
||||||
|
// Console.WriteLine(data.BestAskPrice);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
Secrets.cs.bkp
Normal file
5
Secrets.cs.bkp
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
public static class Secrets{
|
||||||
|
public const string BINANCE_API_PK = "";
|
||||||
|
public const string BINANCE_API_SK = "";
|
||||||
|
public const string TELEGRAM_BOT_TOKEN = "";
|
||||||
|
}
|
||||||
16
SignalsTestCmd.csproj
Normal file
16
SignalsTestCmd.csproj
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.2" />
|
||||||
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.0" />
|
||||||
|
|
||||||
|
<PackageReference Include="BinanceDotNet" Version="4.12.0" />
|
||||||
|
<PackageReference Include="Telegram.Bot" Version="19.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
24
SignalsTestCmd.sln
Normal file
24
SignalsTestCmd.sln
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.5.2.0
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalsTestCmd", "SignalsTestCmd.csproj", "{D2CBB26B-D565-FEEC-1B33-96397A5C8843}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{D2CBB26B-D565-FEEC-1B33-96397A5C8843}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D2CBB26B-D565-FEEC-1B33-96397A5C8843}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D2CBB26B-D565-FEEC-1B33-96397A5C8843}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D2CBB26B-D565-FEEC-1B33-96397A5C8843}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {4DB50F9B-E9B0-4716-B6ED-52066149F1F8}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
156
TAReport.cs
Normal file
156
TAReport.cs
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
using BinanceExchange.API.Models.Response;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SignalsTest;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SignalsTest
|
||||||
|
{
|
||||||
|
public class TAReport
|
||||||
|
{
|
||||||
|
public string pair;
|
||||||
|
public int interval;
|
||||||
|
[JsonIgnore]
|
||||||
|
public KlineCandleStickResponse candle;
|
||||||
|
public decimal Close;
|
||||||
|
public decimal Open;
|
||||||
|
public decimal High;
|
||||||
|
public decimal Low;
|
||||||
|
public DateTime CloseTime;
|
||||||
|
public decimal SMA7;
|
||||||
|
public decimal SMA25;
|
||||||
|
public decimal SMA99;
|
||||||
|
|
||||||
|
public decimal EMA7, EMA25, EMA99;
|
||||||
|
|
||||||
|
public decimal MACD = 0;
|
||||||
|
public decimal EMACD = 0;
|
||||||
|
|
||||||
|
public decimal ATR14;
|
||||||
|
public decimal ATR10;
|
||||||
|
public decimal AVGDiff = 0;
|
||||||
|
|
||||||
|
public decimal STHigh;
|
||||||
|
public decimal STLow;
|
||||||
|
public decimal ST;
|
||||||
|
|
||||||
|
public decimal RSI = 0;
|
||||||
|
|
||||||
|
public bool STUp = false;
|
||||||
|
public bool TGOR=false;
|
||||||
|
public static TAReport Generate(string _pair, int _interval, List<KlineCandleStickResponse> response, int index, List<TAReport> history)
|
||||||
|
{
|
||||||
|
TAReport report = new TAReport();
|
||||||
|
report.pair = _pair;
|
||||||
|
report.interval = _interval;
|
||||||
|
report.candle = response[index];
|
||||||
|
report.Open = response[index].Open;
|
||||||
|
report.Close = response[index].Close;
|
||||||
|
report.High = response[index].High;
|
||||||
|
report.Low = response[index].Low;
|
||||||
|
report.CloseTime = response[index].CloseTime;
|
||||||
|
// foreach(int sma in m_SMA)
|
||||||
|
// {
|
||||||
|
// report.SMAs.Add(sma, Indicators.getSMA(response, index, sma));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// foreach (int ema in m_EMA)
|
||||||
|
// {
|
||||||
|
// report.SMAs.Add(ema, Indicators.getEMA(response, index, 0, ema));
|
||||||
|
// }
|
||||||
|
report.SMA7 = Indicators.getSMA(response, index, 7);
|
||||||
|
report.SMA25 = Indicators.getSMA(response, index, 25);
|
||||||
|
report.SMA99 = Indicators.getSMA(response, index, 99);
|
||||||
|
|
||||||
|
report.EMA7 = Indicators.getEMA(response, index, 0, 7);
|
||||||
|
report.EMA25 = Indicators.getEMA(response, index, 0, 25);
|
||||||
|
report.EMA99 = Indicators.getEMA(response, index, 0, 99);
|
||||||
|
report.MACD = Indicators.getMACD(response, 12, 26, index);
|
||||||
|
|
||||||
|
report.RSI = Indicators.getRSI(response, index);
|
||||||
|
|
||||||
|
if (history == null)
|
||||||
|
{
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
//MACD Signal
|
||||||
|
List<decimal> MACDHistory = new List<decimal>();
|
||||||
|
List<decimal> ATR10History = new List<decimal>();
|
||||||
|
List<decimal> ATR14History = new List<decimal>();
|
||||||
|
|
||||||
|
foreach (TAReport item in history)
|
||||||
|
{
|
||||||
|
MACDHistory.Add(item.MACD);
|
||||||
|
ATR10History.Add(item.ATR10);
|
||||||
|
ATR14History.Add(item.ATR14);
|
||||||
|
}
|
||||||
|
report.EMACD = Indicators.getEMA(MACDHistory, index, 0, 9);
|
||||||
|
|
||||||
|
report.ATR10 = Indicators.getATR(response, 10, index, ATR10History);
|
||||||
|
report.ATR14 = Indicators.getATR(response, 14, index, ATR14History);
|
||||||
|
|
||||||
|
// SuperTrend Multiplier
|
||||||
|
decimal multiplier = 3;
|
||||||
|
|
||||||
|
// Basic Upper and Lower Bands
|
||||||
|
decimal basicUpperBand = (response[index].High + response[index].Low) / 2 + multiplier * report.ATR14;
|
||||||
|
decimal basicLowerBand = (response[index].High + response[index].Low) / 2 - multiplier * report.ATR10;
|
||||||
|
|
||||||
|
// Initialize Final Upper and Lower Bands
|
||||||
|
decimal finalUpperBand = basicUpperBand;
|
||||||
|
decimal finalLowerBand = basicLowerBand;
|
||||||
|
|
||||||
|
// Adjust Final Upper and Lower Bands based on previous history
|
||||||
|
if (index > 0)
|
||||||
|
{
|
||||||
|
finalUpperBand = (history[index - 1].Close <= history[index - 1].STHigh)
|
||||||
|
? Math.Min(basicUpperBand, history[index - 1].STHigh)
|
||||||
|
: basicUpperBand;
|
||||||
|
|
||||||
|
finalLowerBand = (history[index - 1].Close >= history[index - 1].STLow)
|
||||||
|
? Math.Max(basicLowerBand, history[index - 1].STLow)
|
||||||
|
: basicLowerBand;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool currentTrendUp = true;
|
||||||
|
|
||||||
|
if (index > 0)
|
||||||
|
{
|
||||||
|
if (history[index - 1].STUp) // If the previous trend was up
|
||||||
|
{
|
||||||
|
currentTrendUp = (response[index].Close > finalLowerBand); // Price > Final Lower Band => Stay up
|
||||||
|
}
|
||||||
|
else // If the previous trend was down
|
||||||
|
{
|
||||||
|
currentTrendUp = (response[index].Close >= finalUpperBand); // Price >= Final Upper Band => Flip to up
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Assign SuperTrend values to the report
|
||||||
|
report.STHigh = finalUpperBand;
|
||||||
|
report.STLow = finalLowerBand;
|
||||||
|
report.STUp = currentTrendUp;
|
||||||
|
report.ST = currentTrendUp ? finalLowerBand : finalUpperBand;
|
||||||
|
|
||||||
|
report.TGOR= Patterns.GetTGOR(response, index);
|
||||||
|
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class CustomExtensions
|
||||||
|
{
|
||||||
|
|
||||||
|
public static string toJson(this TAReport report)
|
||||||
|
{
|
||||||
|
return JsonConvert.SerializeObject(report, Formatting.Indented);
|
||||||
|
}
|
||||||
|
}
|
||||||
65
Utils.cs
Normal file
65
Utils.cs
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
using BinanceExchange.API.Enums;
|
||||||
|
using BinanceExchange.API.Models.Response;
|
||||||
|
using BinanceExchange.API.Models.WebSocket;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SignalsTest
|
||||||
|
{
|
||||||
|
public class Utils
|
||||||
|
{
|
||||||
|
public static int GetMinutesForInterval(KlineInterval interval)
|
||||||
|
|
||||||
|
{
|
||||||
|
switch (interval)
|
||||||
|
{
|
||||||
|
case KlineInterval.OneMinute:
|
||||||
|
return 1;
|
||||||
|
case KlineInterval.ThreeMinutes:
|
||||||
|
return 3;
|
||||||
|
case KlineInterval.FiveMinutes:
|
||||||
|
return 5;
|
||||||
|
case KlineInterval.FifteenMinutes:
|
||||||
|
return 15;
|
||||||
|
case KlineInterval.ThirtyMinutes:
|
||||||
|
return 30;
|
||||||
|
case KlineInterval.OneHour:
|
||||||
|
return 60;
|
||||||
|
case KlineInterval.TwoHours:
|
||||||
|
return 120;
|
||||||
|
case KlineInterval.FourHours:
|
||||||
|
return 240;
|
||||||
|
case KlineInterval.EightHours:
|
||||||
|
return 60 * 8;
|
||||||
|
case KlineInterval.TwelveHours:
|
||||||
|
return 60 * 12;
|
||||||
|
case KlineInterval.SixHours:
|
||||||
|
return 60 * 6;
|
||||||
|
case KlineInterval.OneDay:
|
||||||
|
return 60 * 24;
|
||||||
|
case KlineInterval.ThreeDays:
|
||||||
|
return 60 * 24 * 3;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KlineCandleStickResponse KlineToResponse(BinanceKlineData data)
|
||||||
|
{
|
||||||
|
KlineCandleStickResponse response = new KlineCandleStickResponse();
|
||||||
|
response.Open = data.Kline.Open;
|
||||||
|
response.Close = data.Kline.Close;
|
||||||
|
response.CloseTime = data.Kline.EndTime;
|
||||||
|
response.OpenTime = data.Kline.StartTime;
|
||||||
|
response.High = data.Kline.High;
|
||||||
|
response.Low = data.Kline.Low;
|
||||||
|
response.Volume = data.Kline.Volume;
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user