GMX v2 - Trading (#7)

* Move PrivateKeys.cs

* Update gitignore

* Update gitignore

* updt

* Extract GmxServiceTests.cs

* Refact

* update todo

* Update code

* Fix hashdata

* Replace static token hashed datas

* Set allowance

* Add get orders

* Add get orders tests

* Add ignore

* add close orders

* revert

* Add get gas limit

* Start increasePosition. Todo: Finish GetExecutionFee and estimateGas

* little refact

* Update gitignore

* Fix namespaces and clean repo

* Add tests samples

* Add execution fee

* Add increase position

* Handle backtest on the frontend

* Add tests

* Update increase

* Test increase

* fix increase

* Fix size

* Start get position

* Update get positions

* Fix get position

* Update rpc and trade mappers

* Finish close position

* Fix leverage
This commit is contained in:
Oda
2025-01-30 23:06:22 +07:00
committed by GitHub
parent ecaa89c67b
commit 65bdb8e34f
156 changed files with 11253 additions and 4073 deletions

View File

@@ -16,7 +16,8 @@ namespace Managing.Infrastructure.Exchanges
private readonly ICandleRepository _candleRepository;
private readonly IEnumerable<IExchangeProcessor> _exchangeProcessor;
public ExchangeService(ILogger<ExchangeService> logger, ICandleRepository candleRepository, IEnumerable<IExchangeProcessor> processor)
public ExchangeService(ILogger<ExchangeService> logger, ICandleRepository candleRepository,
IEnumerable<IExchangeProcessor> processor)
{
_logger = logger;
_candleRepository = candleRepository;
@@ -24,6 +25,7 @@ namespace Managing.Infrastructure.Exchanges
}
#region Trades
public async Task<Trade> OpenTrade(
Account account,
Ticker ticker,
@@ -37,31 +39,55 @@ namespace Managing.Infrastructure.Exchanges
DateTime? currentDate = null,
bool ioc = true)
{
_logger.LogInformation($"OpenMarketTrade - {ticker} - Type: {tradeType} - {direction} - Price: {price} - Quantity: {quantity} - Leverage: {leverage}");
_logger.LogInformation(
$"OpenMarketTrade - {ticker} - Type: {tradeType} - {direction} - Price: {price} - Quantity: {quantity} - Leverage: {leverage}");
if (isForPaperTrading)
{
return BuildEmptyTrade(ticker, price, quantity, direction, leverage, tradeType, currentDate.Value, reduceOnly ? TradeStatus.PendingOpen : TradeStatus.Filled);
return BuildEmptyTrade(ticker, price, quantity, direction, leverage, tradeType, currentDate.Value,
reduceOnly ? TradeStatus.PendingOpen : TradeStatus.Filled);
}
var processor = GetProcessor(account);
return await processor.OpenTrade(account, ticker, direction, price, quantity, leverage, tradeType, reduceOnly, isForPaperTrading, currentDate, ioc);
return await processor.OpenTrade(account, ticker, direction, price, quantity, leverage, tradeType,
reduceOnly, isForPaperTrading, currentDate, ioc);
}
private IExchangeProcessor GetProcessor(Account account)
{
return _exchangeProcessor.First(e => e.Exchange() == account.Exchange);
var exchange = EvmTradingExchangesList.Contains(account.Exchange) ? TradingExchanges.Evm : account.Exchange;
return _exchangeProcessor.First(e => e.Exchange() == exchange);
}
public Trade BuildEmptyTrade(Ticker ticker, decimal price, decimal quantity, TradeDirection direction, decimal? leverage, TradeType tradeType,
private static List<TradingExchanges> EvmTradingExchangesList
{
get
{
var eligibileProcessors = new List<TradingExchanges>()
{
TradingExchanges.Evm, TradingExchanges.GmxV2
};
return eligibileProcessors;
}
}
private bool IsEvmExchange(Account account)
{
return EvmTradingExchangesList.Contains(account.Exchange);
}
public Trade BuildEmptyTrade(Ticker ticker, decimal price, decimal quantity, TradeDirection direction,
decimal? leverage, TradeType tradeType,
DateTime dateTime, TradeStatus tradeStatus)
{
return new Trade(dateTime, direction, tradeStatus, tradeType, ticker, quantity, price, leverage,
Guid.NewGuid().ToString(), "EmptyTrade");
}
public async Task<Trade> OpenStopLoss(Account account, Ticker ticker, TradeDirection originalDirection, decimal stopLossPrice,
decimal quantity, bool isForPaperTrading = false, DateTime? currentDate = null)
public async Task<Trade> OpenStopLoss(Account account, Ticker ticker, TradeDirection originalDirection,
decimal stopLossPrice,
decimal quantity, bool isForPaperTrading = false, DateTime? currentDate = null)
{
return await OpenTrade(
account,
@@ -75,8 +101,9 @@ namespace Managing.Infrastructure.Exchanges
reduceOnly: true);
}
public async Task<Trade> OpenTakeProfit(Account account, Ticker ticker, TradeDirection originalDirection, decimal takeProfitPrice,
decimal quantity, bool isForPaperTrading = false, DateTime? currentDate = null)
public async Task<Trade> OpenTakeProfit(Account account, Ticker ticker, TradeDirection originalDirection,
decimal takeProfitPrice,
decimal quantity, bool isForPaperTrading = false, DateTime? currentDate = null)
{
return await OpenTrade(
account,
@@ -90,9 +117,12 @@ namespace Managing.Infrastructure.Exchanges
reduceOnly: true);
}
public Task<Trade> ClosePosition(Account account, Position position, decimal lastPrice, bool isForPaperTrading = false)
public async Task<Trade> ClosePosition(Account account, Position position, decimal lastPrice,
bool isForPaperTrading = false)
{
var direction = position.OriginDirection == TradeDirection.Long ? TradeDirection.Short : TradeDirection.Long;
var direction = position.OriginDirection == TradeDirection.Long
? TradeDirection.Short
: TradeDirection.Long;
if (isForPaperTrading)
{
@@ -104,11 +134,11 @@ namespace Managing.Infrastructure.Exchanges
TradeType.Market,
position.Open.Date,
TradeStatus.Filled);
return Task.FromResult(fake);
return fake;
}
var processor = GetProcessor(account);
var closedTrade = processor.OpenTrade(
var closedTrade = await processor.OpenTrade(
account,
position.Ticker,
direction,
@@ -116,15 +146,18 @@ namespace Managing.Infrastructure.Exchanges
position.Open.Quantity,
position.Open.Leverage,
tradeType: TradeType.Market,
reduceOnly: true).Result;
reduceOnly: true);
if (account.Exchange != Common.Enums.TradingExchanges.Evm)
if (!IsEvmExchange(account))
{
closedTrade.Price = processor.GetTrade(account, closedTrade.ExchangeOrderId, closedTrade.Ticker).Result.Price;
// Only use for non-EVM exchanges since the call to the blockchain is async
closedTrade.Price = processor.GetTrade(account, closedTrade.ExchangeOrderId, closedTrade.Ticker).Result
.Price;
}
return Task.FromResult(closedTrade);
return closedTrade;
}
#endregion
@@ -142,13 +175,13 @@ namespace Managing.Infrastructure.Exchanges
public async Task<Trade> GetTrade(string reference, string orderId, Ticker ticker)
{
var processor = _exchangeProcessor.First(e => e.Exchange() == Common.Enums.TradingExchanges.Evm);
var processor = _exchangeProcessor.First(e => e.Exchange() == TradingExchanges.Evm);
return await processor.GetTrade(reference, orderId, ticker);
}
public Task<List<FundingRate>> GetFundingRates()
{
var processor = _exchangeProcessor.First(e => e.Exchange() == Common.Enums.TradingExchanges.Evm);
var processor = _exchangeProcessor.First(e => e.Exchange() == TradingExchanges.Evm);
return processor.GetFundingRates();
}
@@ -156,16 +189,17 @@ namespace Managing.Infrastructure.Exchanges
{
var processor = GetProcessor(account);
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)
{
var processor = GetProcessor(account);
return await processor.GetCandles(account, ticker, startDate, timeframe);
}
public async Task<List<Candle>> GetCandlesInflux(TradingExchanges exchange, Ticker ticker, DateTime startDate, Timeframe timeframe)
public async Task<List<Candle>> GetCandlesInflux(TradingExchanges exchange, Ticker ticker, DateTime startDate,
Timeframe timeframe)
{
var candlesFromRepo = await _candleRepository.GetCandles(exchange, ticker, timeframe, startDate);
return candlesFromRepo.ToList();
@@ -214,13 +248,15 @@ namespace Managing.Infrastructure.Exchanges
public async Task<List<Ticker>> GetTickers(Account account, Timeframe timeframe)
{
var tickers = await _candleRepository.GetTickersAsync(account.Exchange, timeframe, DateTime.UtcNow.AddDays(-2));
var tickers =
await _candleRepository.GetTickersAsync(account.Exchange, timeframe, DateTime.UtcNow.AddDays(-2));
return tickers.ToList();
}
public decimal GetBestPrice(Account account, Ticker ticker, decimal lastPrice, decimal quantity, TradeDirection direction)
public decimal GetBestPrice(Account account, Ticker ticker, decimal lastPrice, decimal quantity,
TradeDirection direction)
{
if (account.Exchange == Common.Enums.TradingExchanges.Evm)
if (IsEvmExchange(account))
{
return GetPrice(account, ticker, DateTime.UtcNow);
}
@@ -246,4 +282,4 @@ namespace Managing.Infrastructure.Exchanges
return await processor.GetOrders(account, ticker);
}
}
}
}