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"),
|
Predicate = r => r.Tags.Contains("live"),
|
||||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
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();
|
app.Run();
|
||||||
@@ -20,7 +20,7 @@ public interface IEvmManager
|
|||||||
Task<List<EvmBalance>> GetAllBalancesOnAllChain(string publicAddress);
|
Task<List<EvmBalance>> GetAllBalancesOnAllChain(string publicAddress);
|
||||||
|
|
||||||
Task<List<Candle>> GetCandles(Ticker ticker, DateTime startDate,
|
Task<List<Candle>> GetCandles(Ticker ticker, DateTime startDate,
|
||||||
Timeframe interval);
|
Timeframe interval, bool isFirstCall = false);
|
||||||
|
|
||||||
decimal GetVolume(SubgraphProvider subgraphProvider, Ticker ticker);
|
decimal GetVolume(SubgraphProvider subgraphProvider, Ticker ticker);
|
||||||
Task<List<Ticker>> GetAvailableTicker();
|
Task<List<Ticker>> GetAvailableTicker();
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public interface IExchangeService
|
|||||||
Task<List<Balance>> GetBalances(Account account, bool isForPaperTrading = false);
|
Task<List<Balance>> GetBalances(Account account, bool isForPaperTrading = false);
|
||||||
decimal GetPrice(Account account, Ticker ticker, DateTime date);
|
decimal GetPrice(Account account, Ticker ticker, DateTime date);
|
||||||
Task<Trade> GetTrade(Account account, string order, Ticker ticker);
|
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,
|
Task<Trade> OpenStopLoss(Account account, Ticker ticker, TradeDirection originalDirection, decimal stopLossPrice,
|
||||||
decimal quantity, bool isForPaperTrading = false, DateTime? currentDate = null);
|
decimal quantity, bool isForPaperTrading = false, DateTime? currentDate = null);
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1"/>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Managing.Application.Abstractions\Managing.Application.Abstractions.csproj" />
|
<ProjectReference Include="..\Managing.Application.Abstractions\Managing.Application.Abstractions.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Managing.Application">
|
||||||
|
<HintPath>..\Managing.Api\bin\Debug\net8.0\Managing.Application.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Managing.Application.Abstractions.Repositories;
|
using Managing.Application.Abstractions.Repositories;
|
||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
using Managing.Application.Workers.Abstractions;
|
using Managing.Application.Workers.Abstractions;
|
||||||
|
using Managing.Domain.Candles;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
|
|
||||||
@@ -38,7 +39,16 @@ public class PricesService : IPricesService
|
|||||||
await _candleRepository.GetCandles(exchange, ticker, timeframe, DateTime.UtcNow.AddDays(-2));
|
await _candleRepository.GetCandles(exchange, ticker, timeframe, DateTime.UtcNow.AddDays(-2));
|
||||||
var lastCandle = lastCandles.LastOrDefault();
|
var lastCandle = lastCandles.LastOrDefault();
|
||||||
var startDate = lastCandle != null ? lastCandle.Date : new DateTime(2017, 1, 1);
|
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 candles = !lastCandles.Any() ? newCandles : newCandles.Where(c => c.Date > lastCandle?.Date);
|
||||||
var candlesInserted = 0;
|
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.Abstractions.Services;
|
||||||
using Managing.Application.Workers.Abstractions;
|
using Managing.Application.Workers.Abstractions;
|
||||||
using Managing.Domain.Accounts;
|
using Managing.Domain.Accounts;
|
||||||
@@ -23,6 +24,7 @@ public class StatisticService : IStatisticService
|
|||||||
private readonly IBacktester _backtester;
|
private readonly IBacktester _backtester;
|
||||||
private readonly ITradaoService _tradaoService;
|
private readonly ITradaoService _tradaoService;
|
||||||
private readonly IMessengerService _messengerService;
|
private readonly IMessengerService _messengerService;
|
||||||
|
private readonly ICacheService _cacheService;
|
||||||
private readonly ILogger<StatisticService> _logger;
|
private readonly ILogger<StatisticService> _logger;
|
||||||
|
|
||||||
public StatisticService(
|
public StatisticService(
|
||||||
@@ -34,7 +36,8 @@ public class StatisticService : IStatisticService
|
|||||||
ITradingService tradingService,
|
ITradingService tradingService,
|
||||||
IBacktester backtester,
|
IBacktester backtester,
|
||||||
ITradaoService tradaoService,
|
ITradaoService tradaoService,
|
||||||
IMessengerService messengerService)
|
IMessengerService messengerService,
|
||||||
|
ICacheService cacheService)
|
||||||
{
|
{
|
||||||
_exchangeService = exchangeService;
|
_exchangeService = exchangeService;
|
||||||
_accountService = accountService;
|
_accountService = accountService;
|
||||||
@@ -45,6 +48,7 @@ public class StatisticService : IStatisticService
|
|||||||
_backtester = backtester;
|
_backtester = backtester;
|
||||||
_tradaoService = tradaoService;
|
_tradaoService = tradaoService;
|
||||||
_messengerService = messengerService;
|
_messengerService = messengerService;
|
||||||
|
_cacheService = cacheService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateTopVolumeTicker(TradingExchanges exchange, int top)
|
public async Task UpdateTopVolumeTicker(TradingExchanges exchange, int top)
|
||||||
@@ -159,7 +163,16 @@ public class StatisticService : IStatisticService
|
|||||||
|
|
||||||
public async Task<IList<Ticker>> GetTickers()
|
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()
|
public async Task UpdateSpotlight()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Managing.Domain.Candles;
|
|||||||
using Managing.Domain.Statistics;
|
using Managing.Domain.Statistics;
|
||||||
using Managing.Domain.Trades;
|
using Managing.Domain.Trades;
|
||||||
using Managing.Infrastructure.Exchanges.Abstractions;
|
using Managing.Infrastructure.Exchanges.Abstractions;
|
||||||
|
using Managing.Infrastructure.Exchanges.Exchanges;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
|
|
||||||
@@ -199,10 +200,15 @@ namespace Managing.Infrastructure.Exchanges
|
|||||||
return await processor.GetTrades(account, ticker);
|
return await processor.GetTrades(account, ticker);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate,
|
public async Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate, Timeframe timeframe, bool isFirstCall)
|
||||||
Timeframe timeframe)
|
|
||||||
{
|
{
|
||||||
var processor = GetProcessor(account);
|
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);
|
return await processor.GetCandles(account, ticker, startDate, timeframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ public class EvmProcessor : BaseProcessor
|
|||||||
return await _evmManager.GetCandles(ticker, startDate, interval);
|
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)
|
public override decimal GetFee(Account account, bool isForPaperTrading = false)
|
||||||
{
|
{
|
||||||
return _evmManager.GetFee(Constants.Chains.Arbitrum).Result;
|
return _evmManager.GetFee(Constants.Chains.Arbitrum).Result;
|
||||||
|
|||||||
@@ -336,20 +336,43 @@ public class EvmManager : IEvmManager
|
|||||||
return chainBalances;
|
return chainBalances;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<Candle>> GetCandles(Ticker ticker, DateTime startDate,
|
public async Task<List<Candle>> GetCandles(Ticker ticker, DateTime startDate, Timeframe timeframe,
|
||||||
Timeframe timeframe)
|
bool isFirstCall = false)
|
||||||
{
|
{
|
||||||
string gmxTimeframe = GmxHelpers.GeTimeframe(timeframe);
|
string gmxTimeframe = GmxHelpers.GeTimeframe(timeframe);
|
||||||
var gmxPrices = await _httpClient.GetFromJsonAsync<GmxV2Prices>(
|
int limit = isFirstCall ? 10000 : CalculateCandleLimit(startDate, timeframe);
|
||||||
$"https://arbitrum-api.gmxinfra.io/prices/candles?tokenSymbol={ticker}&period={gmxTimeframe}&limit=10000");
|
|
||||||
|
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)
|
if (gmxPrices == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var filteredCandles = gmxPrices.Candles.Where(p => p[0] >= startDate.ToUnixTimestamp()).ToList();
|
var filteredCandles = gmxPrices.Candles.Where(p => p[0] >= startDate.ToUnixTimestamp()).ToList();
|
||||||
|
|
||||||
var candles = new List<Candle>();
|
var candles = new List<Candle>();
|
||||||
|
|
||||||
var timeBetweenCandles =
|
var timeBetweenCandles =
|
||||||
gmxPrices.Candles.Count > 2 ? gmxPrices.Candles[0][0] - gmxPrices.Candles[1][0] : 900; // Default 15 minutes
|
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();
|
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)
|
public decimal GetVolume(SubgraphProvider subgraphProvider, Ticker ticker)
|
||||||
{
|
{
|
||||||
var subgraph = GetSubgraph(subgraphProvider);
|
var subgraph = GetSubgraph(subgraphProvider);
|
||||||
@@ -850,4 +892,10 @@ public class EvmManager : IEvmManager
|
|||||||
await _web3ProxyService.CallPrivyServiceAsync<PrivySigningResponse>("sign-message", requestBody);
|
await _web3ProxyService.CallPrivyServiceAsync<PrivySigningResponse>("sign-message", requestBody);
|
||||||
return response.Signature;
|
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)
|
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 marketInfo = getMarketInfoFromTicker(ticker, marketsInfoData);
|
||||||
const collateralToken = getTokenDataFromTicker("USDC", tokensData); // Using USDC as collateral
|
const collateralToken = getTokenDataFromTicker("USDC", tokensData); // Using USDC as collateral
|
||||||
console.log('collateralToken', collateralToken)
|
|
||||||
|
|
||||||
// Calculate the collateral amount in USDC (quantity * price)
|
// Calculate the collateral amount in USDC (quantity * price)
|
||||||
const collateralAmount = BigInt(Math.floor((quantity || 0) * (price || 0) * 1e6)); // USDC has 6 decimals
|
const collateralAmount = BigInt(Math.floor((quantity || 0) * (price || 0) * 1e6)); // USDC has 6 decimals
|
||||||
@@ -325,8 +324,6 @@ export const cancelGmxOrdersImpl = async (
|
|||||||
tokensData
|
tokensData
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('ordersData', ordersData)
|
|
||||||
|
|
||||||
// Extract order keys for the specified ticker
|
// Extract order keys for the specified ticker
|
||||||
const orderKeys = Object.values(ordersData.ordersInfoData)
|
const orderKeys = Object.values(ordersData.ordersInfoData)
|
||||||
.filter(order => {
|
.filter(order => {
|
||||||
@@ -341,8 +338,6 @@ export const cancelGmxOrdersImpl = async (
|
|||||||
return true; // No orders to cancel
|
return true; // No orders to cancel
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('orderKeys', orderKeys)
|
|
||||||
|
|
||||||
// Cancel orders using the batch method
|
// Cancel orders using the batch method
|
||||||
await sdk.orders.cancelOrders(orderKeys);
|
await sdk.orders.cancelOrders(orderKeys);
|
||||||
|
|
||||||
@@ -455,8 +450,6 @@ export const closeGmxPositionImpl = async (
|
|||||||
showPnlInLeverage: true
|
showPnlInLeverage: true
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('positionsInfo', positionsInfo)
|
|
||||||
console.log('direction', direction)
|
|
||||||
// Find the specific position to close
|
// Find the specific position to close
|
||||||
const positionKey = Object.keys(positionsInfo).find(key => {
|
const positionKey = Object.keys(positionsInfo).find(key => {
|
||||||
const position = positionsInfo[key];
|
const position = positionsInfo[key];
|
||||||
@@ -503,8 +496,6 @@ export const closeGmxPositionImpl = async (
|
|||||||
triggerPrice: position.markPrice,
|
triggerPrice: position.markPrice,
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log('params', params)
|
|
||||||
|
|
||||||
const params2 = {
|
const params2 = {
|
||||||
marketInfo,
|
marketInfo,
|
||||||
marketsInfoData,
|
marketsInfoData,
|
||||||
|
|||||||
Reference in New Issue
Block a user