Sviluppo TradingBot
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DesktopBot.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Misura la latenza (ping) verso l'endpoint di trading Alpaca.
|
||||
/// Usa una richiesta GET su /v2/clock che è leggera e non richiede
|
||||
/// autenticazione nella versione pubblica.
|
||||
/// </summary>
|
||||
public class AlpacaPingService : IDisposable
|
||||
{
|
||||
// endpoint pubblico leggero di Alpaca (non richiede auth, risponde 200)
|
||||
private const string PingUrlPaper = "https://paper-api.alpaca.markets/v2/clock";
|
||||
private const string PingUrlLive = "https://api.alpaca.markets/v2/clock";
|
||||
|
||||
private readonly HttpClient _http;
|
||||
private CancellationTokenSource _cts;
|
||||
private bool _isPaper = true;
|
||||
|
||||
public event EventHandler<PingResult> PingCompleted;
|
||||
|
||||
public AlpacaPingService()
|
||||
{
|
||||
_http = new HttpClient { Timeout = TimeSpan.FromSeconds(8) };
|
||||
}
|
||||
|
||||
public void SetEnvironment(bool isPaper) => _isPaper = isPaper;
|
||||
|
||||
public void Start(int intervalSeconds = 10)
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_cts = new CancellationTokenSource();
|
||||
_ = PingLoopAsync(intervalSeconds, _cts.Token);
|
||||
}
|
||||
|
||||
public void Stop() => _cts?.Cancel();
|
||||
|
||||
private async Task PingLoopAsync(int intervalSeconds, CancellationToken ct)
|
||||
{
|
||||
// Prima misura immediata
|
||||
await MeasureAsync();
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
try { await Task.Delay(TimeSpan.FromSeconds(intervalSeconds), ct); }
|
||||
catch (OperationCanceledException) { return; }
|
||||
await MeasureAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task MeasureAsync()
|
||||
{
|
||||
string url = _isPaper ? PingUrlPaper : PingUrlLive;
|
||||
var sw = Stopwatch.StartNew();
|
||||
try
|
||||
{
|
||||
using var req = new HttpRequestMessage(HttpMethod.Head, url);
|
||||
using var resp = await _http.SendAsync(req).ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
PingCompleted?.Invoke(this, new PingResult
|
||||
{
|
||||
LatencyMs = (int)sw.ElapsedMilliseconds,
|
||||
IsSuccess = resp.IsSuccessStatusCode || (int)resp.StatusCode == 403 // 403 = raggiungibile ma senza auth
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
sw.Stop();
|
||||
PingCompleted?.Invoke(this, new PingResult
|
||||
{
|
||||
LatencyMs = -1,
|
||||
IsSuccess = false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_http?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public class PingResult
|
||||
{
|
||||
/// <summary>Latenza in millisecondi. -1 se non raggiungibile.</summary>
|
||||
public int LatencyMs { get; set; }
|
||||
public bool IsSuccess { get; set; }
|
||||
|
||||
public PingStatus Status =>
|
||||
!IsSuccess ? PingStatus.Offline :
|
||||
LatencyMs < 80 ? PingStatus.Good :
|
||||
LatencyMs < 250 ? PingStatus.Fair :
|
||||
PingStatus.Poor;
|
||||
}
|
||||
|
||||
public enum PingStatus { Good, Fair, Poor, Offline }
|
||||
}
|
||||
Reference in New Issue
Block a user