Fix worker cancelled on worker + Cache tickers
This commit is contained in:
@@ -249,24 +249,6 @@ app.UseEndpoints(endpoints =>
|
||||
Predicate = r => r.Tags.Contains("live"),
|
||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||
});
|
||||
|
||||
endpoints.MapHealthChecks("/health/candles", new HealthCheckOptions
|
||||
{
|
||||
Predicate = r => r.Tags.Contains("candles"),
|
||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||
});
|
||||
|
||||
endpoints.MapHealthChecks("/health/gmx", new HealthCheckOptions
|
||||
{
|
||||
Predicate = r => r.Name == "gmx-connectivity",
|
||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||
});
|
||||
|
||||
endpoints.MapHealthChecks("/health/web3proxy", new HealthCheckOptions
|
||||
{
|
||||
Predicate = r => r.Name == "web3proxy",
|
||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||
});
|
||||
});
|
||||
|
||||
app.Run();
|
||||
@@ -20,7 +20,7 @@ public interface IEvmManager
|
||||
Task<List<EvmBalance>> GetAllBalancesOnAllChain(string publicAddress);
|
||||
|
||||
Task<List<Candle>> GetCandles(Ticker ticker, DateTime startDate,
|
||||
Timeframe interval);
|
||||
Timeframe interval, bool isFirstCall = false);
|
||||
|
||||
decimal GetVolume(SubgraphProvider subgraphProvider, Ticker ticker);
|
||||
Task<List<Ticker>> GetAvailableTicker();
|
||||
|
||||
@@ -27,7 +27,7 @@ public interface IExchangeService
|
||||
Task<List<Balance>> GetBalances(Account account, bool isForPaperTrading = false);
|
||||
decimal GetPrice(Account account, Ticker ticker, DateTime date);
|
||||
Task<Trade> GetTrade(Account account, string order, Ticker ticker);
|
||||
Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate, Timeframe interval);
|
||||
Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate, Timeframe interval, bool isFirstCall);
|
||||
|
||||
Task<Trade> OpenStopLoss(Account account, Ticker ticker, TradeDirection originalDirection, decimal stopLossPrice,
|
||||
decimal quantity, bool isForPaperTrading = false, DateTime? currentDate = null);
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1"/>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Managing.Application.Abstractions\Managing.Application.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Managing.Application.Abstractions\Managing.Application.Abstractions.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Managing.Application">
|
||||
<HintPath>..\Managing.Api\bin\Debug\net8.0\Managing.Application.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Managing.Application.Abstractions.Repositories;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Application.Workers.Abstractions;
|
||||
using Managing.Domain.Candles;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
@@ -38,7 +39,16 @@ public class PricesService : IPricesService
|
||||
await _candleRepository.GetCandles(exchange, ticker, timeframe, DateTime.UtcNow.AddDays(-2));
|
||||
var lastCandle = lastCandles.LastOrDefault();
|
||||
var startDate = lastCandle != null ? lastCandle.Date : new DateTime(2017, 1, 1);
|
||||
var newCandles = await _exchangeService.GetCandles(account, ticker, startDate, timeframe);
|
||||
|
||||
List<Candle> newCandles;
|
||||
if (!lastCandles.Any())
|
||||
{
|
||||
newCandles = await _exchangeService.GetCandles(account, ticker, startDate, timeframe, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
newCandles = await _exchangeService.GetCandles(account, ticker, startDate, timeframe, false);
|
||||
}
|
||||
|
||||
var candles = !lastCandles.Any() ? newCandles : newCandles.Where(c => c.Date > lastCandle?.Date);
|
||||
var candlesInserted = 0;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Managing.Application.Abstractions.Repositories;
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Application.Abstractions.Repositories;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Application.Workers.Abstractions;
|
||||
using Managing.Domain.Accounts;
|
||||
@@ -23,6 +24,7 @@ public class StatisticService : IStatisticService
|
||||
private readonly IBacktester _backtester;
|
||||
private readonly ITradaoService _tradaoService;
|
||||
private readonly IMessengerService _messengerService;
|
||||
private readonly ICacheService _cacheService;
|
||||
private readonly ILogger<StatisticService> _logger;
|
||||
|
||||
public StatisticService(
|
||||
@@ -34,7 +36,8 @@ public class StatisticService : IStatisticService
|
||||
ITradingService tradingService,
|
||||
IBacktester backtester,
|
||||
ITradaoService tradaoService,
|
||||
IMessengerService messengerService)
|
||||
IMessengerService messengerService,
|
||||
ICacheService cacheService)
|
||||
{
|
||||
_exchangeService = exchangeService;
|
||||
_accountService = accountService;
|
||||
@@ -45,6 +48,7 @@ public class StatisticService : IStatisticService
|
||||
_backtester = backtester;
|
||||
_tradaoService = tradaoService;
|
||||
_messengerService = messengerService;
|
||||
_cacheService = cacheService;
|
||||
}
|
||||
|
||||
public async Task UpdateTopVolumeTicker(TradingExchanges exchange, int top)
|
||||
@@ -159,7 +163,16 @@ public class StatisticService : IStatisticService
|
||||
|
||||
public async Task<IList<Ticker>> GetTickers()
|
||||
{
|
||||
return await _evmManager.GetAvailableTicker();
|
||||
var cachedTickers = _cacheService.GetValue<List<Ticker>>("tickers");
|
||||
|
||||
if (cachedTickers != null)
|
||||
{
|
||||
return cachedTickers;
|
||||
}
|
||||
|
||||
var tickers = await _evmManager.GetAvailableTicker();
|
||||
_cacheService.SaveValue("tickers", tickers, TimeSpan.FromDays(1));
|
||||
return tickers;
|
||||
}
|
||||
|
||||
public async Task UpdateSpotlight()
|
||||
|
||||
@@ -5,6 +5,7 @@ using Managing.Domain.Candles;
|
||||
using Managing.Domain.Statistics;
|
||||
using Managing.Domain.Trades;
|
||||
using Managing.Infrastructure.Exchanges.Abstractions;
|
||||
using Managing.Infrastructure.Exchanges.Exchanges;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
@@ -199,10 +200,15 @@ namespace Managing.Infrastructure.Exchanges
|
||||
return await processor.GetTrades(account, ticker);
|
||||
}
|
||||
|
||||
public async Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate,
|
||||
Timeframe timeframe)
|
||||
public async Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate, Timeframe timeframe, bool isFirstCall)
|
||||
{
|
||||
var processor = GetProcessor(account);
|
||||
// Only EvmProcessor supports isFirstCall
|
||||
if (processor is EvmProcessor evmProcessor)
|
||||
{
|
||||
return await evmProcessor.GetCandles(account, ticker, startDate, timeframe, isFirstCall);
|
||||
}
|
||||
// Fallback to default behavior for other processors
|
||||
return await processor.GetCandles(account, ticker, startDate, timeframe);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,11 @@ public class EvmProcessor : BaseProcessor
|
||||
return await _evmManager.GetCandles(ticker, startDate, interval);
|
||||
}
|
||||
|
||||
public async Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate, Timeframe interval, bool isFirstCall)
|
||||
{
|
||||
return await _evmManager.GetCandles(ticker, startDate, interval, isFirstCall);
|
||||
}
|
||||
|
||||
public override decimal GetFee(Account account, bool isForPaperTrading = false)
|
||||
{
|
||||
return _evmManager.GetFee(Constants.Chains.Arbitrum).Result;
|
||||
|
||||
@@ -336,20 +336,43 @@ public class EvmManager : IEvmManager
|
||||
return chainBalances;
|
||||
}
|
||||
|
||||
public async Task<List<Candle>> GetCandles(Ticker ticker, DateTime startDate,
|
||||
Timeframe timeframe)
|
||||
public async Task<List<Candle>> GetCandles(Ticker ticker, DateTime startDate, Timeframe timeframe,
|
||||
bool isFirstCall = false)
|
||||
{
|
||||
string gmxTimeframe = GmxHelpers.GeTimeframe(timeframe);
|
||||
var gmxPrices = await _httpClient.GetFromJsonAsync<GmxV2Prices>(
|
||||
$"https://arbitrum-api.gmxinfra.io/prices/candles?tokenSymbol={ticker}&period={gmxTimeframe}&limit=10000");
|
||||
int limit = isFirstCall ? 10000 : CalculateCandleLimit(startDate, timeframe);
|
||||
|
||||
GmxV2Prices? gmxPrices = null;
|
||||
int maxRetries = 3;
|
||||
int delayMs = 1000;
|
||||
|
||||
for (int attempt = 1; attempt <= maxRetries; attempt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
gmxPrices = await _httpClient.GetFromJsonAsync<GmxV2Prices>(
|
||||
$"https://arbitrum-api.gmxinfra.io/prices/candles?tokenSymbol={ticker}&period={gmxTimeframe}&limit={limit}");
|
||||
break;
|
||||
}
|
||||
catch (HttpRequestException ex) when (ex.InnerException is IOException)
|
||||
{
|
||||
Console.Error.WriteLine($"Attempt {attempt}: Network error while fetching candles: {ex.Message}");
|
||||
if (attempt == maxRetries)
|
||||
throw;
|
||||
await Task.Delay(delayMs * attempt);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine($"Unexpected error: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (gmxPrices == null)
|
||||
return null;
|
||||
|
||||
var filteredCandles = gmxPrices.Candles.Where(p => p[0] >= startDate.ToUnixTimestamp()).ToList();
|
||||
|
||||
var candles = new List<Candle>();
|
||||
|
||||
var timeBetweenCandles =
|
||||
gmxPrices.Candles.Count > 2 ? gmxPrices.Candles[0][0] - gmxPrices.Candles[1][0] : 900; // Default 15 minutes
|
||||
|
||||
@@ -362,6 +385,25 @@ public class EvmManager : IEvmManager
|
||||
return candles.OrderBy(c => c.Date).ToList();
|
||||
}
|
||||
|
||||
private int CalculateCandleLimit(DateTime startDate, Timeframe timeframe)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var minutesPerCandle = timeframe switch
|
||||
{
|
||||
Timeframe.OneMinute => 1,
|
||||
Timeframe.FiveMinutes => 5,
|
||||
Timeframe.FifteenMinutes => 15,
|
||||
Timeframe.ThirtyMinutes => 30,
|
||||
Timeframe.OneHour => 60,
|
||||
Timeframe.FourHour => 240,
|
||||
Timeframe.OneDay => 1440,
|
||||
_ => 15
|
||||
};
|
||||
var totalMinutes = (now - startDate).TotalMinutes;
|
||||
var candlesNeeded = (int)Math.Ceiling(totalMinutes / minutesPerCandle);
|
||||
return Math.Min(candlesNeeded + 5, 10000);
|
||||
}
|
||||
|
||||
public decimal GetVolume(SubgraphProvider subgraphProvider, Ticker ticker)
|
||||
{
|
||||
var subgraph = GetSubgraph(subgraphProvider);
|
||||
@@ -850,4 +892,10 @@ public class EvmManager : IEvmManager
|
||||
await _web3ProxyService.CallPrivyServiceAsync<PrivySigningResponse>("sign-message", requestBody);
|
||||
return response.Signature;
|
||||
}
|
||||
|
||||
// Overload to match IEvmManager interface
|
||||
public async Task<List<Candle>> GetCandles(Ticker ticker, DateTime startDate, Timeframe timeframe)
|
||||
{
|
||||
return await GetCandles(ticker, startDate, timeframe, false);
|
||||
}
|
||||
}
|
||||
@@ -139,7 +139,7 @@ internal static class GmxV2Mappers
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Could not parse ticker for symbol {t.Symbol}: {e.Message}");
|
||||
//Console.WriteLine($"Could not parse ticker for symbol {t.Symbol}: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -196,7 +196,6 @@ export const openGmxPositionImpl = async (
|
||||
|
||||
const marketInfo = getMarketInfoFromTicker(ticker, marketsInfoData);
|
||||
const collateralToken = getTokenDataFromTicker("USDC", tokensData); // Using USDC as collateral
|
||||
console.log('collateralToken', collateralToken)
|
||||
|
||||
// Calculate the collateral amount in USDC (quantity * price)
|
||||
const collateralAmount = BigInt(Math.floor((quantity || 0) * (price || 0) * 1e6)); // USDC has 6 decimals
|
||||
@@ -325,8 +324,6 @@ export const cancelGmxOrdersImpl = async (
|
||||
tokensData
|
||||
});
|
||||
|
||||
console.log('ordersData', ordersData)
|
||||
|
||||
// Extract order keys for the specified ticker
|
||||
const orderKeys = Object.values(ordersData.ordersInfoData)
|
||||
.filter(order => {
|
||||
@@ -341,8 +338,6 @@ export const cancelGmxOrdersImpl = async (
|
||||
return true; // No orders to cancel
|
||||
}
|
||||
|
||||
console.log('orderKeys', orderKeys)
|
||||
|
||||
// Cancel orders using the batch method
|
||||
await sdk.orders.cancelOrders(orderKeys);
|
||||
|
||||
@@ -455,8 +450,6 @@ export const closeGmxPositionImpl = async (
|
||||
showPnlInLeverage: true
|
||||
});
|
||||
|
||||
console.log('positionsInfo', positionsInfo)
|
||||
console.log('direction', direction)
|
||||
// Find the specific position to close
|
||||
const positionKey = Object.keys(positionsInfo).find(key => {
|
||||
const position = positionsInfo[key];
|
||||
@@ -503,8 +496,6 @@ export const closeGmxPositionImpl = async (
|
||||
triggerPrice: position.markPrice,
|
||||
}
|
||||
|
||||
//console.log('params', params)
|
||||
|
||||
const params2 = {
|
||||
marketInfo,
|
||||
marketsInfoData,
|
||||
|
||||
Reference in New Issue
Block a user