257 lines
9.0 KiB
C#
257 lines
9.0 KiB
C#
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.Runtime.InteropServices;
|
|
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 List<decimal> resistancePoints = new List<decimal>();
|
|
public List<decimal> supportPoints = new List<decimal>();
|
|
|
|
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()
|
|
{
|
|
candles = new List<KlineCandleStickResponse>();
|
|
|
|
int rounds = 1;
|
|
int candleLimit = 150;
|
|
int intervalInMinutes = Utils.GetMinutesForInterval(interval);
|
|
if (Utils.GetMinutesForInterval(interval) > 50)
|
|
{
|
|
rounds = 10;
|
|
}else if(Utils.GetMinutesForInterval(interval) > 5){
|
|
rounds = 5;
|
|
}
|
|
|
|
for (int i = 0; i < rounds; i++)
|
|
{
|
|
DateTime startTime = DateTime.Now.AddMinutes(-intervalInMinutes * candleLimit * (rounds-i));
|
|
DateTime endTime = startTime.AddMinutes(intervalInMinutes * candleLimit);
|
|
GetKlinesCandlesticksRequest req = new GetKlinesCandlesticksRequest
|
|
{
|
|
Interval = interval,
|
|
Symbol = pair,
|
|
StartTime = startTime,
|
|
EndTime = endTime,
|
|
Limit = candleLimit
|
|
};
|
|
|
|
// Calculate and set the start time for this request
|
|
req.StartTime = req.EndTime.Value.AddMinutes(-intervalInMinutes * candleLimit);
|
|
|
|
Console.WriteLine($"Fetching kandles for {req.Symbol} (Round {i + 1}/{rounds}): {candles.Count} candles retrieved so far.");
|
|
|
|
var response = await Brian.Client.GetKlinesCandlesticks(req);
|
|
candles.AddRange(response);
|
|
|
|
// Update endTime for the next round
|
|
endTime = req.StartTime.Value;
|
|
|
|
// Respect the API rate limit
|
|
await Task.Delay(1500);
|
|
}
|
|
Console.WriteLine($"Completed fetching kandles. Total candles retrieved from {candles[0].OpenTime} to {candles[candles.Count-1].OpenTime}");
|
|
kickstarted = true;
|
|
Analyze(pair);
|
|
}
|
|
|
|
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;
|
|
|
|
if(candles.Count < 100){return;}
|
|
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);
|
|
|
|
}
|
|
string lineCalSMA = "SMA20";
|
|
if(interval!=KlineInterval.FifteenMinutes){
|
|
lineCalSMA= "SMA50";
|
|
}
|
|
resistancePoints = Confirmations.GetResistanceLevels(reports,SMA:lineCalSMA);
|
|
supportPoints = Confirmations.GetSupportiveLevels(reports, SMA:lineCalSMA);
|
|
|
|
for(int i=0; i < reports.Count;i++){
|
|
reports[i].isBullFlag = Confirmations.IsBullFlag(reports, i);
|
|
reports[i].RelativeVolumeIndex = Confirmations.GetRelativeVolumeIndex(reports,i);
|
|
|
|
reports[i].isVwapShort = Patterns.isVwapShort(reports, i);
|
|
reports[i].isVwapLong = Patterns.isVwapLong(reports,i);
|
|
}
|
|
|
|
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 (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
{
|
|
triggers += "test";
|
|
}
|
|
|
|
// 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 (reports[reports.Count - 2].TWS > 1)
|
|
// {
|
|
// triggers += $"Three White Soldiers appeared\n";
|
|
// }
|
|
// if (reports[reports.Count - 2].TBC > 1)
|
|
// {
|
|
// triggers += $"Three Black Crows appeared\n";
|
|
// }
|
|
// if(reports[reports.Count-2].isHammer){
|
|
// triggers+=$"Hammer candle appeared\n";
|
|
// }
|
|
// if(reports[reports.Count-2].isInverseHammer){
|
|
// triggers+=$"Inverse Hammer candle appeared\n";
|
|
// }
|
|
// if(reports[reports.Count-2].isBullFlag){
|
|
// triggers+=$"Possible Bull Flag\n";
|
|
// }
|
|
|
|
if(reports[reports.Count-2].isVwapShort){
|
|
triggers+=$"VWAP Short Signal\n";
|
|
}
|
|
if(reports[reports.Count-2].isVwapLong){
|
|
triggers+=$"VWAP Long Signal\n";
|
|
}
|
|
if (triggers != "")
|
|
{
|
|
List<TAReport> limitedReports = new List<TAReport>(reports);
|
|
int maxCandlesForChart = 150;
|
|
if(limitedReports.Count> maxCandlesForChart){
|
|
limitedReports.RemoveRange(0,limitedReports.Count-maxCandlesForChart-1);
|
|
}
|
|
Picasso.DrawChart(limitedReports, symbol, interval);
|
|
|
|
string message = $"`{symbol}` [{Utils.GetMinutesForInterval(interval)}m] {triggers} \nCurrent price: {reports[reports.Count - 1].Close}";
|
|
Messenger.instance.ScheduleMessage(message, symbol, Utils.GetMinutesForInterval(interval).ToString());
|
|
}
|
|
|
|
}
|
|
|
|
async void KeepUpdatingCandles()
|
|
{
|
|
int delay = (index * 500);
|
|
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;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|