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