Postgres (#30)

* Add postgres

* Migrate users

* Migrate geneticRequest

* Try to fix Concurrent call

* Fix asyncawait

* Fix async and concurrent

* Migrate backtests

* Add cache for user by address

* Fix backtest migration

* Fix not open connection

* Fix backtest command error

* Fix concurrent

* Fix all concurrency

* Migrate TradingRepo

* Fix scenarios

* Migrate statistic repo

* Save botbackup

* Add settings et moneymanagement

* Add bot postgres

* fix a bit more backups

* Fix bot model

* Fix loading backup

* Remove cache market for read positions

* Add workers to postgre

* Fix workers api

* Reduce get Accounts for workers

* Migrate synth to postgre

* Fix backtest saved

* Remove mongodb

* botservice decorrelation

* Fix tradingbot scope call

* fix tradingbot

* fix concurrent

* Fix scope for genetics

* Fix account over requesting

* Fix bundle backtest worker

* fix a lot of things

* fix tab backtest

* Remove optimized moneymanagement

* Add light signal to not use User and too much property

* Make money management lighter

* insert indicators to awaitable

* Migrate add strategies to await

* Refactor scenario and indicator retrieval to use asynchronous methods throughout the application

* add more async await

* Add services

* Fix and clean

* Fix bot a bit

* Fix bot and add message for cooldown

* Remove fees

* Add script to deploy db

* Update dfeeploy script

* fix script

* Add idempotent script and backup

* finish script migration

* Fix did user and agent name on start bot
This commit is contained in:
Oda
2025-07-27 15:42:17 +02:00
committed by GitHub
parent 361bfbf6e8
commit 422fecea7b
294 changed files with 23953 additions and 7272 deletions

View File

@@ -1,5 +1,4 @@
using Managing.Common;
using Managing.Domain.Accounts;
using Managing.Domain.Accounts;
using Managing.Domain.Candles;
using Managing.Domain.Statistics;
using Managing.Domain.Trades;
@@ -9,7 +8,7 @@ namespace Managing.Infrastructure.Exchanges.Abstractions;
public interface IExchangeProcessor
{
public Enums.TradingExchanges Exchange();
public TradingExchanges Exchange();
void LoadClient(Account account);
Task<Trade> OpenTrade(
Account account,
@@ -27,7 +26,7 @@ public interface IExchangeProcessor
decimal? takeProfitPrice = null);
Task<decimal> GetBalance(Account account, bool isForPaperTrading = false);
Task<List<Balance>> GetBalances(Account account, bool isForPaperTrading = false);
decimal GetPrice(Account account, Ticker ticker, DateTime date);
Task<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);
decimal GetVolume(Account account, Ticker ticker);

View File

@@ -1,52 +1,12 @@
using Binance.Net.Interfaces;
using FTX.Net.Objects.Models;
using Kraken.Net.Objects.Models;
using Managing.Domain.Candles;
using Managing.Infrastructure.Databases.MongoDb.Collections;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Exchanges
{
public static class CandleHelpers
{
public static CandleDto Convert(IBinanceKline candle, Ticker ticker, Timeframe timeframe)
{
return new CandleDto()
{
Ticker = ticker.ToString(),
Timeframe = timeframe,
BaseVolume = candle.Volume,
Close = candle.ClosePrice,
CloseTime = candle.CloseTime,
Open = candle.OpenPrice,
OpenTime = candle.OpenTime,
High = candle.HighPrice,
Low = candle.LowPrice,
QuoteVolume = candle.QuoteVolume,
TakerBuyBaseVolume = candle.TakerBuyBaseVolume,
TakerBuyQuoteVolume = candle.TakerBuyQuoteVolume,
TradeCount = candle.TradeCount,
};
}
public static CandleDto Convert(KrakenStreamKline candle, Ticker ticker, Timeframe timeframe)
{
return new CandleDto()
{
Ticker = ticker.ToString(),
Timeframe = timeframe,
BaseVolume = candle.Volume,
Close = candle.ClosePrice,
CloseTime = candle.CloseTime,
Open = candle.OpenPrice,
OpenTime = candle.OpenTime,
High = candle.HighPrice,
Low = candle.LowPrice,
QuoteVolume = candle.VolumeWeightedAveragePrice,
TradeCount = candle.TradeCount
};
}
internal static Candle Map(FTXKline lastCandle)
{
return new Candle
@@ -65,18 +25,14 @@ namespace Managing.Infrastructure.Exchanges
{
Ticker = ticker.ToString(),
Timeframe = timeframe,
BaseVolume = candle.Volume,
Volume = candle.Volume,
Close = candle.ClosePrice,
Date = candle.CloseTime,
Open = candle.OpenPrice,
OpenTime = candle.OpenTime,
High = candle.HighPrice,
Low = candle.LowPrice,
QuoteVolume = candle.QuoteVolume,
TakerBuyBaseVolume = candle.TakerBuyBaseVolume,
TakerBuyQuoteVolume = candle.TakerBuyQuoteVolume,
TradeCount = candle.TradeCount,
};
}
}
}
}

View File

@@ -243,10 +243,10 @@ namespace Managing.Infrastructure.Exchanges
return processor.GetFee(account);
}
public decimal GetPrice(Account account, Ticker ticker, DateTime date)
public async Task<decimal> GetPrice(Account account, Ticker ticker, DateTime date)
{
var processor = GetProcessor(account);
return processor.GetPrice(account, ticker, date);
return await processor.GetPrice(account, ticker, date);
}
public Candle GetCandle(Account account, Ticker ticker, DateTime date)
@@ -274,12 +274,12 @@ namespace Managing.Infrastructure.Exchanges
return tickers.ToList();
}
public decimal GetBestPrice(Account account, Ticker ticker, decimal lastPrice, decimal quantity,
public async Task<decimal> GetBestPrice(Account account, Ticker ticker, decimal lastPrice, decimal quantity,
TradeDirection direction)
{
if (IsEvmExchange(account))
{
return GetPrice(account, ticker, DateTime.UtcNow);
return await GetPrice(account, ticker, DateTime.UtcNow);
}
return GetOrderbook(account, ticker).GetBestPrice(direction, quantity);

View File

@@ -1,5 +1,4 @@
using Managing.Common;
using Managing.Domain.Accounts;
using Managing.Domain.Accounts;
using Managing.Domain.Candles;
using Managing.Domain.Statistics;
using Managing.Domain.Trades;
@@ -12,12 +11,12 @@ namespace Managing.Infrastructure.Exchanges.Exchanges
{
public abstract void LoadClient(Account account);
public abstract Task<bool> CancelOrder(Account account, Ticker ticker);
public abstract Enums.TradingExchanges Exchange();
public abstract TradingExchanges Exchange();
public abstract Task<decimal> GetBalance(Account account, bool isForPaperTrading = false);
public abstract Candle GetCandle(Account account, Ticker ticker, DateTime date);
public abstract Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate, Timeframe interval);
public abstract decimal GetFee(Account account, bool isForPaperTrading = false);
public abstract decimal GetPrice(Account account, Ticker ticker, DateTime date);
public abstract Task<decimal> GetPrice(Account account, Ticker ticker, DateTime date);
public abstract Task<decimal> GetQuantityInPosition(Account account, Ticker ticker);
public abstract Task<Trade> GetTrade(Account account, string order, Ticker ticker);
public abstract Task<List<Trade>> GetTrades(Account account, Ticker ticker);

View File

@@ -1,198 +0,0 @@
using Binance.Net.Clients;
using Binance.Net.Enums;
using Binance.Net.Interfaces.Clients;
using CryptoExchange.Net.Authentication;
using Managing.Common;
using Managing.Core;
using Managing.Domain.Accounts;
using Managing.Domain.Candles;
using Managing.Domain.Statistics;
using Managing.Domain.Trades;
using Managing.Infrastructure.Exchanges.Helpers;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Exchanges.Exchanges;
public class BinanceProcessor : BaseProcessor
{
private ILogger<BinanceProcessor> _logger;
private IBinanceRestClient _binanceClient;
public BinanceProcessor(ILogger<BinanceProcessor> logger)
{
_logger = logger;
}
public override async Task<bool> CancelOrder(Account account, Ticker ticker)
{
var binanceResult =
await _binanceClient.UsdFuturesApi.Trading.CancelAllOrdersAsync(BinanceHelpers.ToBinanceTicker(ticker));
return binanceResult.Success;
}
public override Enums.TradingExchanges Exchange() => Enums.TradingExchanges.Binance;
public override async Task<decimal> GetBalance(Account account, bool isForPaperTrading = false)
{
var balance = 0m;
var binanceBalance = await _binanceClient.UsdFuturesApi.Account.GetBalancesAsync();
foreach (var item in binanceBalance.Data)
{
balance += item.AvailableBalance;
}
return balance;
}
public override Task<List<Balance>> GetBalances(Account account, bool isForPaperTrading = false)
{
throw new NotImplementedException();
}
public override Candle GetCandle(Account account, Ticker ticker, DateTime date)
{
throw new NotImplementedException();
}
public override async Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate,
Timeframe timeframe)
{
var binanceCandles = await _binanceClient.UsdFuturesApi.ExchangeData.GetKlinesAsync(
BinanceHelpers.ToBinanceTicker(ticker),
BinanceHelpers.Map(timeframe), startDate);
return (List<Candle>)binanceCandles.Data.Select(binanceKline =>
BinanceHelpers.Map(binanceKline, ticker, account.Exchange));
}
public override decimal GetFee(Account account, bool isForPaperTrading = false)
{
throw new NotImplementedException();
}
public override Orderbook GetOrderbook(Account account, Ticker ticker)
{
throw new NotImplementedException();
}
public override Task<List<Trade>> GetOrders(Account account, Ticker ticker)
{
throw new NotImplementedException();
}
public override decimal GetPrice(Account account, Ticker ticker, DateTime date)
{
var binancePrice = _binanceClient.UsdFuturesApi.ExchangeData
.GetPriceAsync(BinanceHelpers.ToBinanceTicker(ticker)).Result.Data;
return binancePrice.Price;
}
public override async Task<decimal> GetQuantityInPosition(Account account, Ticker ticker)
{
throw new NotImplementedException();
}
public override async Task<Trade> GetTrade(Account account, string order, Ticker ticker)
{
var binanceOrder =
await _binanceClient.UsdFuturesApi.Trading.GetOrderAsync(BinanceHelpers.ToBinanceTicker(ticker),
origClientOrderId: order);
return BinanceHelpers.Map(binanceOrder.Data);
}
public override Task<Trade> GetTrade(string reference, string orderId, Ticker ticker)
{
throw new NotImplementedException();
}
public override Task<List<FundingRate>> GetFundingRates()
{
throw new NotImplementedException();
}
public override Task<IEnumerable<Position>> GetPositions(Account account)
{
throw new NotImplementedException();
}
public override async Task<List<Trade>> GetTrades(Account account, Ticker ticker)
{
var binanceOrder =
await _binanceClient.UsdFuturesApi.Trading.GetOrdersAsync(BinanceHelpers.ToBinanceTicker(ticker));
return (List<Trade>)binanceOrder.Data.Select(o => BinanceHelpers.Map(o));
}
public override decimal GetVolume(Account account, Ticker ticker)
{
throw new NotImplementedException();
}
public override void LoadClient(Account account)
{
var credentials = new ApiCredentials(account.Key, account.Secret);
_binanceClient = new BinanceRestClient((options) => { options.ApiCredentials = credentials; });
}
public override async Task<Trade> OpenTrade(Account account, Ticker ticker, TradeDirection direction, decimal price,
decimal quantity, decimal? leverage = null, TradeType tradeType = TradeType.Limit, bool reduceOnly = false,
bool isForPaperTrading = false, DateTime? currentDate = null, bool ioc = true,
decimal? stopLossPrice = null,
decimal? takeProfitPrice = null)
{
var trade = new Trade(DateTime.Now, direction, TradeStatus.PendingOpen, tradeType, ticker, quantity, price,
leverage, "", "");
trade.SetQuantity(quantity, GetQuantityPrecision(account, ticker));
trade.SetPrice(price, GetPricePrecision(account, ticker));
if (trade.Quantity <= 0)
throw new InvalidOperationException(
$"Minimum quantity not match, cannot execute trade {direction} for {ticker}.");
var binanceOrderType = BinanceHelpers.BinanceOrderTypeMap(tradeType);
var binanceResult = await _binanceClient.UsdFuturesApi.Trading.PlaceOrderAsync(
BinanceHelpers.ToBinanceTicker(ticker),
direction != TradeDirection.Long ? OrderSide.Sell : OrderSide.Buy,
binanceOrderType,
price: binanceOrderType == FuturesOrderType.Limit ? trade.Price : null,
quantity: trade.Quantity,
reduceOnly: reduceOnly,
priceProtect: true,
timeInForce: binanceOrderType == FuturesOrderType.Limit ? TimeInForce.GoodTillCanceled : null,
activationPrice: binanceOrderType == FuturesOrderType.Limit ? trade.Price : null,
stopPrice: binanceOrderType == FuturesOrderType.StopMarket ? trade.Price : null);
_logger.LogInformation("Exchange result : {0}", JsonConvert.SerializeObject(binanceResult));
var binanceOrderExecuted = BinanceHelpers.Map(binanceResult, leverage);
if (binanceResult.Success)
{
var binanceOrder = await GetTrade(account, "", ticker);
trade.Price = binanceOrder.Price;
trade.SetStatus(binanceOrder.Status);
trade.SetExchangeOrderId("");
trade.SetMessage("");
}
return trade;
}
private int GetPricePrecision(Account account, Ticker ticker)
{
var binanceFutureInfo = _binanceClient.UsdFuturesApi.ExchangeData.GetExchangeInfoAsync().Result.Data;
var precision = binanceFutureInfo.Symbols.Single(p => p.Name == BinanceHelpers.ToBinanceTicker(ticker))
.PriceFilter.TickSize;
return MathHelpers.GetDecimalPlaces(precision);
}
private int GetQuantityPrecision(Account account, Ticker ticker)
{
var binanceFutureInfo = _binanceClient.UsdFuturesApi.ExchangeData.GetExchangeInfoAsync().Result.Data;
var precision = binanceFutureInfo.Symbols.Single(p => p.Name == BinanceHelpers.ToBinanceTicker(ticker))
.QuantityPrecision;
return Convert.ToInt32(precision);
}
}

View File

@@ -83,9 +83,9 @@ public class EvmProcessor : BaseProcessor
return _evmManager.GetFee(Constants.Chains.Arbitrum).Result;
}
public override decimal GetPrice(Account account, Ticker ticker, DateTime date)
public override async Task<decimal> GetPrice(Account account, Ticker ticker, DateTime date)
{
return GetCandle(account, ticker, date).Close;
return (await GetCandles(account, ticker, date, Timeframe.OneMinute, true)).Last().Close;
}
public override async Task<decimal> GetQuantityInPosition(Account account, Ticker ticker)

View File

@@ -1,220 +0,0 @@
using CryptoExchange.Net.Authentication;
using FTX.Net.Interfaces.Clients;
using FTX.Net.Objects;
using Managing.Common;
using Managing.Domain.Accounts;
using Managing.Domain.Candles;
using Managing.Domain.Statistics;
using Managing.Domain.Trades;
using Managing.Infrastructure.Exchanges.Helpers;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Exchanges.Exchanges;
public class FtxProcessor : BaseProcessor
{
private IFTXClient _ftxClient;
private ILogger<FtxProcessor> _logger;
public FtxProcessor(ILogger<FtxProcessor> logger)
{
_logger = logger;
}
public override Enums.TradingExchanges Exchange() => Enums.TradingExchanges.Ftx;
public override void LoadClient(Account account)
{
var credentials = new ApiCredentials(account.Key, account.Secret);
var ftxConfig = new FTXClientOptions()
{
SubaccountName = account.Name
};
}
public override async Task<bool> CancelOrder(Account account, Ticker ticker)
{
LoadClient(account);
var ftxResult = await _ftxClient.TradeApi.Trading.CancelAllOrdersAsync(FtxHelpers.ToFtxTicker(ticker));
return ftxResult.Success;
}
public override async Task<decimal> GetBalance(Account account, bool isForPaperTrading = false)
{
LoadClient(account);
var balance = 0m;
var ftxBalance = await _ftxClient.TradeApi.Account.GetBalancesAsync();
foreach (var item in ftxBalance.Data)
{
balance += item.UsdValue;
}
return balance;
}
public override Candle GetCandle(Account account, Ticker ticker, DateTime date)
{
LoadClient(account);
var ftxKlines = _ftxClient.TradeApi.ExchangeData.GetKlinesAsync(FtxHelpers.ToFtxTicker(ticker),
FTX.Net.Enums.KlineInterval.OneMinute, date.AddHours(-2.5)).Result.Data;
if (ftxKlines != null && ftxKlines.Any())
{
var lastCandle = ftxKlines.ToList().LastOrDefault();
return CandleHelpers.Map(lastCandle);
}
return null;
}
public override async Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate,
Timeframe timeframe)
{
LoadClient(account);
var candles = new List<Candle>();
var ftxCandles = await _ftxClient.TradeApi.ExchangeData.GetKlinesAsync(FtxHelpers.ToFtxTicker(ticker),
FtxHelpers.Map(timeframe), startDate);
if (ftxCandles.Success)
candles.AddRange(ftxCandles.Data.SkipLast(1)
.Select(ftxKline => FtxHelpers.Map(ftxKline, ticker, account.Exchange, timeframe)));
return candles;
}
public override decimal GetFee(Account account, bool isForPaperTrading = false)
{
LoadClient(account);
var ftxResult = _ftxClient.TradeApi.Account.GetAccountInfoAsync().Result.Data;
return ftxResult.TakerFee;
}
public override decimal GetPrice(Account account, Ticker ticker, DateTime date)
{
LoadClient(account);
var ftxKlines = _ftxClient.TradeApi.ExchangeData.GetKlinesAsync(FtxHelpers.ToFtxTicker(ticker),
FTX.Net.Enums.KlineInterval.OneMinute, date.AddHours(-2.5)).Result.Data;
if (ftxKlines != null && ftxKlines.Any())
{
return ftxKlines.ToList().LastOrDefault().ClosePrice;
}
return 0;
}
public override async Task<decimal> GetQuantityInPosition(Account account, Ticker ticker)
{
var ftxTickerBalance = _ftxClient.TradeApi.Account.GetPositionsAsync().Result.Data;
return ftxTickerBalance.FirstOrDefault(f => f.Future == FtxHelpers.ToFtxTicker(ticker)).Quantity;
}
public override async Task<Trade> GetTrade(Account account, string order, Ticker ticker)
{
LoadClient(account);
var ftxOrder = await _ftxClient.TradeApi.Trading.GetOrderByClientOrderIdAsync(order);
return FtxHelpers.Map(ftxOrder.Data);
}
public override async Task<List<Trade>> GetTrades(Account account, Ticker ticker)
{
LoadClient(account);
var ftxOrder = await _ftxClient.TradeApi.Trading.GetOrdersAsync(ticker.ToString());
return (List<Trade>)ftxOrder.Data.Select(o => FtxHelpers.Map(o));
}
public override decimal GetVolume(Account account, Ticker ticker)
{
var futureStats = _ftxClient.TradeApi.ExchangeData.GetFutureStatsAsync(FtxHelpers.ToFtxTicker(ticker)).Result
.Data;
return futureStats.Volume;
}
public override async Task<Trade> OpenTrade(Account account, Ticker ticker, TradeDirection direction, decimal price,
decimal quantity, decimal? leverage = null, TradeType tradeType = TradeType.Limit, bool reduceOnly = false,
bool isForPaperTrading = false, DateTime? currentDate = null, bool ioc = true,
decimal? stopLossPrice = null,
decimal? takeProfitPrice = null)
{
LoadClient(account);
var trade = new Trade(DateTime.Now, direction, TradeStatus.PendingOpen, tradeType, ticker, quantity, price,
leverage, "", "");
trade.SetQuantity(quantity, 6);
Trade ftxOrder;
if (tradeType == TradeType.StopLoss || tradeType == TradeType.TakeProfitLimit ||
tradeType == TradeType.StopMarket)
{
var ftxTriggerOrderType = FtxHelpers.FtxTriggerOrderTypeMap(tradeType);
var ftxResult = await _ftxClient.TradeApi.Trading.PlaceTriggerOrderAsync(FtxHelpers.ToFtxTicker(ticker),
direction != TradeDirection.Long ? FTX.Net.Enums.OrderSide.Sell : FTX.Net.Enums.OrderSide.Buy,
ftxTriggerOrderType,
triggerPrice: price,
reduceOnly: true,
retryUntilFilled: false,
quantity: quantity);
_logger.LogInformation("Exchange result : {0}", JsonConvert.SerializeObject(ftxResult));
ftxOrder = FtxHelpers.Map(ftxResult, leverage);
}
else
{
var ftxOrderType = FtxHelpers.FtxOrderTypeMap(tradeType);
var ftxResult = await _ftxClient.TradeApi.Trading.PlaceOrderAsync(FtxHelpers.ToFtxTicker(ticker),
direction != TradeDirection.Long ? FTX.Net.Enums.OrderSide.Sell : FTX.Net.Enums.OrderSide.Buy,
ftxOrderType,
price: ftxOrderType == FTX.Net.Enums.OrderType.Limit ? price : null,
quantity: quantity,
clientOrderId: Guid.NewGuid().ToString(),
immediateOrCancel: ioc);
_logger.LogInformation("Exchange result : {0}", JsonConvert.SerializeObject(ftxResult));
ftxOrder = FtxHelpers.Map(ftxResult, leverage);
}
trade.SetStatus(ftxOrder.Status);
trade.SetExchangeOrderId(ftxOrder.ExchangeOrderId);
trade.SetMessage(ftxOrder.Message);
trade.Price = ftxOrder.Price;
return trade;
}
public override Orderbook GetOrderbook(Account account, Ticker ticker)
{
LoadClient(account);
var ftxOrderBook = _ftxClient.TradeApi.ExchangeData.GetOrderBookAsync(FtxHelpers.ToFtxTicker(ticker), 100)
.Result;
return FtxHelpers.Map(ftxOrderBook);
}
public override Task<List<Balance>> GetBalances(Account account, bool isForPaperTrading = false)
{
throw new NotImplementedException();
}
public override Task<List<Trade>> GetOrders(Account acount, Ticker ticker)
{
throw new NotImplementedException();
}
public override Task<Trade> GetTrade(string reference, string orderId, Ticker ticker)
{
throw new NotImplementedException();
}
public override Task<List<FundingRate>> GetFundingRates()
{
throw new NotImplementedException();
}
public override Task<IEnumerable<Position>> GetPositions(Account account)
{
throw new NotImplementedException();
}
}

View File

@@ -1,156 +0,0 @@
using CryptoExchange.Net.Authentication;
using Kraken.Net.Clients;
using Kraken.Net.Interfaces.Clients;
using Kraken.Net.Objects.Options;
using Managing.Common;
using Managing.Domain.Accounts;
using Managing.Domain.Candles;
using Managing.Domain.Statistics;
using Managing.Domain.Trades;
using Managing.Infrastructure.Exchanges.Helpers;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Exchanges.Exchanges;
public class KrakenProcessor : BaseProcessor
{
private ILogger<KrakenProcessor> _logger;
private IKrakenRestClient _krakenClient;
public KrakenProcessor(ILogger<KrakenProcessor> logger)
{
_logger = logger;
}
public override Task<bool> CancelOrder(Account account, Ticker ticker)
{
throw new NotImplementedException();
}
public override Enums.TradingExchanges Exchange() => Enums.TradingExchanges.Kraken;
public override async Task<decimal> GetBalance(Account account, bool isForPaperTrading = false)
{
LoadClient(account);
var balance = await _krakenClient.SpotApi.Account.GetBalancesAsync();
balance.Data.TryGetValue("USDT", out decimal krakenBalance);
return krakenBalance;
}
public override Task<List<Balance>> GetBalances(Account account, bool isForPaperTrading = false)
{
throw new NotImplementedException();
}
public override Candle GetCandle(Account account, Ticker ticker, DateTime date)
{
throw new NotImplementedException();
}
public override Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate,
Timeframe interval)
{
throw new NotImplementedException();
}
public override decimal GetFee(Account account, bool isForPaperTrading = false)
{
throw new NotImplementedException();
}
public override Orderbook GetOrderbook(Account account, Ticker ticker)
{
throw new NotImplementedException();
}
public override Task<List<Trade>> GetOrders(Account account, Ticker ticker)
{
throw new NotImplementedException();
}
public override decimal GetPrice(Account account, Ticker ticker, DateTime date)
{
LoadClient(account);
var krakenKline = _krakenClient.SpotApi.ExchangeData.GetKlinesAsync(ticker.ToString(),
Kraken.Net.Enums.KlineInterval.OneMinute, date).Result.Data.Data.ToList()[0];
return (krakenKline.HighPrice + krakenKline.ClosePrice) / 2;
}
public override Task<decimal> GetQuantityInPosition(Account account, Ticker ticker)
{
throw new NotImplementedException();
}
public override async Task<Trade> GetTrade(Account account, string order, Ticker ticker)
{
LoadClient(account);
var krakenOrder = await _krakenClient.SpotApi.Trading.GetOrderAsync(order);
return KrakenHelpers.Map(krakenOrder.Data.Values.First());
}
public override Task<Trade> GetTrade(string reference, string orderId, Ticker ticker)
{
throw new NotImplementedException();
}
public override Task<List<FundingRate>> GetFundingRates()
{
throw new NotImplementedException();
}
public override Task<IEnumerable<Position>> GetPositions(Account account)
{
throw new NotImplementedException();
}
public override async Task<List<Trade>> GetTrades(Account account, Ticker ticker)
{
LoadClient(account);
var krakenOrder = await _krakenClient.SpotApi.Trading.GetOrdersAsync();
return (List<Trade>)krakenOrder.Data.Select(o => KrakenHelpers.Map(o));
}
public override decimal GetVolume(Account account, Ticker ticker)
{
throw new NotImplementedException();
}
public override void LoadClient(Account account)
{
var credentials = new ApiCredentials(account.Key, account.Secret);
var krakenConfig = new KrakenRestOptions()
{
ApiCredentials = credentials
};
_krakenClient = new KrakenRestClient((options) => { options.ApiCredentials = krakenConfig.ApiCredentials; });
}
public override async Task<Trade> OpenTrade(Account account, Ticker ticker, TradeDirection direction, decimal price,
decimal quantity, decimal? leverage = null, TradeType tradeType = TradeType.Limit, bool reduceOnly = false,
bool isForPaperTrading = false, DateTime? currentDate = null, bool ioc = true,
decimal? stopLossPrice = null,
decimal? takeProfitPrice = null)
{
LoadClient(account);
var trade = new Trade(DateTime.Now, direction, TradeStatus.PendingOpen, tradeType, ticker, quantity, price,
leverage, "", "");
trade.SetQuantity(quantity, 6);
trade.SetPrice(price, 1);
var order = await _krakenClient.SpotApi.Trading.PlaceOrderAsync(ticker.ToString(),
direction != TradeDirection.Long ? Kraken.Net.Enums.OrderSide.Sell : Kraken.Net.Enums.OrderSide.Buy,
KrakenHelpers.KrakenOrderTypeMap(tradeType),
price: price,
quantity: quantity,
leverage: leverage);
_logger.LogInformation("Exchange result : {0}", JsonConvert.SerializeObject(order));
var krakenOrderExecuted = GetTrade(account, ((string[])order.Data.OrderIds)[0], ticker).Result;
trade.SetStatus(krakenOrderExecuted.Status);
trade.SetExchangeOrderId(krakenOrderExecuted.ExchangeOrderId);
trade.SetMessage(krakenOrderExecuted.Message);
return trade;
}
}

View File

@@ -2,7 +2,6 @@
using Binance.Net.Interfaces;
using Binance.Net.Objects.Models.Futures;
using CryptoExchange.Net.Objects;
using Managing.Common;
using Managing.Core;
using Managing.Domain.Candles;
using Managing.Domain.Trades;
@@ -73,22 +72,18 @@ namespace Managing.Infrastructure.Exchanges.Helpers
"", result.Error?.Message);
}
public static Candle Map(IBinanceKline binanceKline, Ticker ticker, Enums.TradingExchanges exchange)
public static Candle Map(IBinanceKline binanceKline, Ticker ticker, TradingExchanges exchange)
{
return new Candle
{
Date = binanceKline.CloseTime,
BaseVolume = binanceKline.Volume,
Volume = binanceKline.Volume,
Close = binanceKline.ClosePrice,
High = binanceKline.HighPrice,
Low = binanceKline.LowPrice,
Open = binanceKline.OpenPrice,
Ticker = ticker.ToString(),
QuoteVolume = binanceKline.QuoteVolume,
TradeCount = binanceKline.TradeCount,
OpenTime = binanceKline.OpenTime,
TakerBuyBaseVolume = binanceKline.TakerBuyBaseVolume,
TakerBuyQuoteVolume = binanceKline.TakerBuyQuoteVolume,
Exchange = exchange
};
}

View File

@@ -1,7 +1,6 @@
using CryptoExchange.Net.Objects;
using FTX.Net.Enums;
using FTX.Net.Objects.Models;
using Managing.Common;
using Managing.Core;
using Managing.Domain.Candles;
using Managing.Domain.Trades;
@@ -178,13 +177,13 @@ namespace Managing.Infrastructure.Exchanges.Helpers
public static Candle Map(
FTXKline ftxKline,
Ticker ticker,
Enums.TradingExchanges exchange,
TradingExchanges exchange,
Timeframe timeframe)
{
return new Candle
{
Date = ftxKline.OpenTime,
BaseVolume = ftxKline.Volume ?? 0,
Volume = ftxKline.Volume ?? 0,
Close = ftxKline.ClosePrice,
High = ftxKline.HighPrice,
Low = ftxKline.LowPrice,