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

@@ -1,5 +1,7 @@
using static Managing.Common.Enums;
namespace Managing.Domain.Bots;
public class BotBackup
{
public string Name { get; set; }

View File

@@ -1,5 +1,4 @@
using Managing.Application.Strategies;
using Managing.Domain.Strategies;
using Managing.Domain.Strategies;
using static Managing.Common.Enums;
namespace Managing.Domain.Scenarios;
@@ -14,16 +13,25 @@ public static class ScenarioHelpers
IStrategy result = strategy.Type switch
{
StrategyType.StDev => new StDevContext(strategy.Name, strategy.Timeframe, strategy.Period.Value),
StrategyType.RsiDivergence => new RSIDivergenceStrategy(strategy.Name, strategy.Timeframe, strategy.Period.Value),
StrategyType.RsiDivergenceConfirm => new RSIDivergenceConfirmStrategy(strategy.Name, strategy.Timeframe, strategy.Period.Value),
StrategyType.MacdCross => new MACDCrossStrategy(strategy.Name, strategy.Timeframe, strategy.FastPeriods.Value, strategy.SlowPeriods.Value, strategy.SignalPeriods.Value),
StrategyType.RsiDivergence => new RSIDivergenceStrategy(strategy.Name, strategy.Timeframe,
strategy.Period.Value),
StrategyType.RsiDivergenceConfirm => new RSIDivergenceConfirmStrategy(strategy.Name, strategy.Timeframe,
strategy.Period.Value),
StrategyType.MacdCross => new MACDCrossStrategy(strategy.Name, strategy.Timeframe,
strategy.FastPeriods.Value, strategy.SlowPeriods.Value, strategy.SignalPeriods.Value),
StrategyType.EmaCross => new EmaCrossStrategy(strategy.Name, strategy.Timeframe, strategy.Period.Value),
StrategyType.ThreeWhiteSoldiers => new ThreeWhiteSoldiersStrategy(strategy.Name, strategy.Timeframe, strategy.Period.Value),
StrategyType.SuperTrend => new SuperTrendStrategy(strategy.Name, strategy.Timeframe, strategy.Period.Value, strategy.Multiplier.Value),
StrategyType.ChandelierExit => new ChandelierExitStrategy(strategy.Name, strategy.Timeframe, strategy.Period.Value, strategy.Multiplier.Value),
StrategyType.ThreeWhiteSoldiers => new ThreeWhiteSoldiersStrategy(strategy.Name, strategy.Timeframe,
strategy.Period.Value),
StrategyType.SuperTrend => new SuperTrendStrategy(strategy.Name, strategy.Timeframe,
strategy.Period.Value, strategy.Multiplier.Value),
StrategyType.ChandelierExit => new ChandelierExitStrategy(strategy.Name, strategy.Timeframe,
strategy.Period.Value, strategy.Multiplier.Value),
StrategyType.EmaTrend => new EmaTrendStrategy(strategy.Name, strategy.Timeframe, strategy.Period.Value),
StrategyType.StochRsiTrend => new StochRsiTrendStrategy(strategy.Name, strategy.Timeframe, strategy.Period.Value, strategy.StochPeriods.Value, strategy.SignalPeriods.Value, strategy.SmoothPeriods.Value),
StrategyType.Stc => new STCStrategy(strategy.Name, strategy.Timeframe, strategy.CyclePeriods.Value, strategy.FastPeriods.Value, strategy.SlowPeriods.Value),
StrategyType.StochRsiTrend => new StochRsiTrendStrategy(strategy.Name, strategy.Timeframe,
strategy.Period.Value, strategy.StochPeriods.Value, strategy.SignalPeriods.Value,
strategy.SmoothPeriods.Value),
StrategyType.Stc => new STCStrategy(strategy.Name, strategy.Timeframe, strategy.CyclePeriods.Value,
strategy.FastPeriods.Value, strategy.SlowPeriods.Value),
_ => throw new NotImplementedException(),
};
@@ -63,11 +71,13 @@ public static class ScenarioHelpers
{
strategy.Period = period.Value;
}
break;
case StrategyType.MacdCross:
if (!fastPeriods.HasValue || !slowPeriods.HasValue || !signalPeriods.HasValue)
{
throw new Exception($"Missing fastPeriods or slowPeriods or signalPeriods, for {strategy.Type} strategy type");
throw new Exception(
$"Missing fastPeriods or slowPeriods or signalPeriods, for {strategy.Type} strategy type");
}
else
{
@@ -75,6 +85,7 @@ public static class ScenarioHelpers
strategy.SlowPeriods = slowPeriods;
strategy.SignalPeriods = signalPeriods;
}
break;
break;
case StrategyType.ThreeWhiteSoldiers:
@@ -90,6 +101,7 @@ public static class ScenarioHelpers
strategy.Period = period;
strategy.Multiplier = multiplier;
}
break;
case StrategyType.StochRsiTrend:
if (!period.HasValue
@@ -97,7 +109,8 @@ public static class ScenarioHelpers
|| !signalPeriods.HasValue
|| !smoothPeriods.HasValue)
{
throw new Exception($"Missing period, stochPeriods, signalPeriods, smoothPeriods for {strategy.Type} strategy type");
throw new Exception(
$"Missing period, stochPeriods, signalPeriods, smoothPeriods for {strategy.Type} strategy type");
}
else
{
@@ -106,11 +119,13 @@ public static class ScenarioHelpers
strategy.SignalPeriods = signalPeriods;
strategy.SmoothPeriods = smoothPeriods;
}
break;
case StrategyType.Stc:
if (!fastPeriods.HasValue || !slowPeriods.HasValue || !cyclePeriods.HasValue)
{
throw new Exception($"Missing fastPeriods or slowPeriods or cyclePeriods, for {strategy.Type} strategy type");
throw new Exception(
$"Missing fastPeriods or slowPeriods or cyclePeriods, for {strategy.Type} strategy type");
}
else
{
@@ -118,6 +133,7 @@ public static class ScenarioHelpers
strategy.SlowPeriods = slowPeriods;
strategy.CyclePeriods = cyclePeriods;
}
break;
default:
break;
@@ -145,4 +161,4 @@ public static class ScenarioHelpers
_ => throw new NotImplementedException(),
};
}
}
}

View File

@@ -9,7 +9,8 @@ namespace Managing.Domain.Shared.Helpers;
public static class TradingBox
{
public static Signal GetSignal(HashSet<Candle> newCandles, HashSet<IStrategy> strategies, HashSet<Signal> previousSignal)
public static Signal GetSignal(HashSet<Candle> newCandles, HashSet<IStrategy> strategies,
HashSet<Signal> previousSignal)
{
var signalOnCandles = new HashSet<Signal>();
foreach (var strategy in strategies)
@@ -35,10 +36,12 @@ public static class TradingBox
return null;
var data = newCandles.First();
return ComputeSignals(strategies, signalOnCandles, MiscExtensions.ParseEnum<Ticker>(data.Ticker), data.Timeframe);
return ComputeSignals(strategies, signalOnCandles, MiscExtensions.ParseEnum<Ticker>(data.Ticker),
data.Timeframe);
}
public static Signal ComputeSignals(HashSet<IStrategy> strategies, HashSet<Signal> signalOnCandles, Ticker ticker, Timeframe timeframe)
public static Signal ComputeSignals(HashSet<IStrategy> strategies, HashSet<Signal> signalOnCandles, Ticker ticker,
Timeframe timeframe)
{
Signal signal = null;
if (strategies.Count > 1)
@@ -49,34 +52,36 @@ public static class TradingBox
var validContext = true;
if (contextStrategiesCount > 0 &&
signalOnCandles.Count(s => s.SignalType == SignalType.Context) != contextStrategiesCount)
signalOnCandles.Count(s => s.SignalType == SignalType.Context) != contextStrategiesCount)
{
validContext = false;
}
if (signals.All(s => s.Direction == TradeDirection.Long) && trendSignal.All(t => t.Direction == TradeDirection.Long) && validContext)
if (signals.All(s => s.Direction == TradeDirection.Long) &&
trendSignal.All(t => t.Direction == TradeDirection.Long) && validContext)
{
signal = new Signal(
ticker,
TradeDirection.Long,
Confidence.High,
signals.Last().Candle,
signals.Last().Date,
signals.Last().Exchange,
timeframe,
StrategyType.Composite, SignalType.Signal);
ticker,
TradeDirection.Long,
Confidence.High,
signals.Last().Candle,
signals.Last().Date,
signals.Last().Exchange,
timeframe,
StrategyType.Composite, SignalType.Signal);
}
else if (signals.All(s => s.Direction == TradeDirection.Short) && trendSignal.All(t => t.Direction == TradeDirection.Short) && validContext)
else if (signals.All(s => s.Direction == TradeDirection.Short) &&
trendSignal.All(t => t.Direction == TradeDirection.Short) && validContext)
{
signal = new Signal(
ticker,
TradeDirection.Short,
Confidence.High,
signals.Last().Candle,
signals.Last().Date,
signals.Last().Exchange,
timeframe,
StrategyType.Composite, SignalType.Signal);
ticker,
TradeDirection.Short,
Confidence.High,
signals.Last().Candle,
signals.Last().Date,
signals.Last().Exchange,
timeframe,
StrategyType.Composite, SignalType.Signal);
}
}
else
@@ -88,7 +93,8 @@ public static class TradingBox
return signal;
}
public static MoneyManagement GetBestMoneyManagement(List<Candle> candles, List<Position> positions, MoneyManagement originMoneyManagement)
public static MoneyManagement GetBestMoneyManagement(List<Candle> candles, List<Position> positions,
MoneyManagement originMoneyManagement)
{
// Foreach positions, identitify the price when the position is open
// Then, foreach candles, get the maximum price before the next position
@@ -120,11 +126,13 @@ public static class TradingBox
return moneyManagement;
}
public static (decimal Stoploss, decimal TakeProfit) GetBestSLTPForPosition(List<Candle> candles, Position position, Position nextPosition)
public static (decimal Stoploss, decimal TakeProfit) GetBestSLTPForPosition(List<Candle> candles, Position position,
Position nextPosition)
{
var stopLoss = 0M;
var takeProfit = 0M;
var candlesBeforeNextPosition = candles.Where(c => c.Date >= position.Date && c.Date <= (nextPosition == null ? candles.Last().Date : nextPosition.Date));
var candlesBeforeNextPosition = candles.Where(c =>
c.Date >= position.Date && c.Date <= (nextPosition == null ? candles.Last().Date : nextPosition.Date));
if (position.OriginDirection == TradeDirection.Long)
{
@@ -140,7 +148,7 @@ public static class TradingBox
stopLoss = GetPercentageFromEntry(position.Open.Price, maxPrice);
takeProfit = GetPercentageFromEntry(position.Open.Price, minPrice);
}
return (stopLoss, takeProfit);
}
@@ -149,13 +157,18 @@ public static class TradingBox
return Math.Abs(100 - ((100 * price) / entry));
}
public static ProfitAndLoss GetProfitAndLoss(Position position, decimal quantity, decimal price)
public static ProfitAndLoss GetProfitAndLoss(Position position, decimal quantity, decimal price, decimal leverage)
{
var orders = new List<Tuple<decimal, decimal>>
{
new Tuple<decimal, decimal>(position.Open.Quantity, position.Open.Price),
new Tuple<decimal, decimal>(-quantity, price)
};
return new ProfitAndLoss(orders, position.OriginDirection);
{
new Tuple<decimal, decimal>(position.Open.Quantity, position.Open.Price),
new Tuple<decimal, decimal>(-quantity, price)
};
var pnl = new ProfitAndLoss(orders, position.OriginDirection);
// Apply leverage on the realized pnl
pnl.Realized = pnl.Realized * leverage;
return pnl;
}
}
}

View File

@@ -1,38 +1,30 @@
using Managing.Domain.Scenarios;
using System.ComponentModel.DataAnnotations;
using Managing.Common;
using Managing.Domain.Scenarios;
using Managing.Domain.Strategies;
using System.ComponentModel.DataAnnotations;
using static Managing.Common.Enums;
namespace Managing.Domain.Statistics;
public class SpotlightOverview
{
[Required]
public List<Spotlight> Spotlights { get; set; }
[Required]
public DateTime DateTime { get; set; }
[Required] public List<Spotlight> Spotlights { get; set; }
[Required] public DateTime DateTime { get; set; }
public Guid Identifier { get; set; }
public int ScenarioCount { get; set; }
}
public class Spotlight
{
[Required]
public Scenario Scenario { get; set; }
[Required]
public List<TickerSignal> TickerSignals { get; set; }
[Required] public Scenario Scenario { get; set; }
[Required] public List<TickerSignal> TickerSignals { get; set; }
}
public class TickerSignal
{
[Required]
public Ticker Ticker { get; set; }
[Required]
public List<Signal> FiveMinutes { get; set; }
[Required]
public List<Signal> FifteenMinutes { get; set; }
[Required]
public List<Signal> OneHour { get; set; }
[Required]
public List<Signal> FourHour { get; set; }
[Required]
public List<Signal> OneDay { get; set; }
[Required] public Enums.Ticker Ticker { get; set; }
[Required] public List<Signal> FiveMinutes { get; set; }
[Required] public List<Signal> FifteenMinutes { get; set; }
[Required] public List<Signal> OneHour { get; set; }
[Required] public List<Signal> FourHour { get; set; }
[Required] public List<Signal> OneDay { get; set; }
}

View File

@@ -1,11 +1,10 @@
using Managing.Core;
using Managing.Domain.Shared.Rules;
using Managing.Domain.Strategies;
using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Application.Strategies;
namespace Managing.Domain.Strategies;
public class EmaCrossStrategy : EmaBaseStrategy
{
@@ -28,20 +27,20 @@ public class EmaCrossStrategy : EmaBaseStrategy
{
var ema = Candles.GetEma(Period.Value).ToList();
var emaCandles = MapEmaToCandle(ema, Candles.TakeLast(Period.Value));
if (ema.Count == 0)
return null;
var previousCandle = emaCandles[0];
foreach (var currentCandle in emaCandles.Skip(1))
{
if (previousCandle.Close > (decimal)currentCandle.Ema &&
if (previousCandle.Close > (decimal)currentCandle.Ema &&
currentCandle.Close < (decimal)currentCandle.Ema)
{
AddSignal(currentCandle, Timeframe, TradeDirection.Short, Confidence.Medium);
}
if (previousCandle.Close < (decimal)currentCandle.Ema &&
if (previousCandle.Close < (decimal)currentCandle.Ema &&
currentCandle.Close > (decimal)currentCandle.Ema)
{
AddSignal(currentCandle, Timeframe, TradeDirection.Long, Confidence.Medium);
@@ -60,10 +59,11 @@ public class EmaCrossStrategy : EmaBaseStrategy
private void AddSignal(CandleEma candleSignal, Timeframe timeframe, TradeDirection direction, Confidence confidence)
{
var signal = new Signal(MiscExtensions.ParseEnum<Ticker>(candleSignal.Ticker), direction, confidence, candleSignal, candleSignal.Date, candleSignal.Exchange, timeframe, Type, SignalType);
var signal = new Signal(MiscExtensions.ParseEnum<Ticker>(candleSignal.Ticker), direction, confidence,
candleSignal, candleSignal.Date, candleSignal.Exchange, timeframe, Type, SignalType);
if (!Signals.Any(s => s.Identifier == signal.Identifier))
{
Signals.AddItem(signal);
}
}
}
}

View File

@@ -1,10 +1,9 @@
using Managing.Domain.Candles;
using Managing.Domain.Shared.Rules;
using Managing.Domain.Strategies;
using Managing.Domain.Strategies.Rules;
using static Managing.Common.Enums;
namespace Managing.Application.Strategies
namespace Managing.Domain.Strategies
{
public class ThreeWhiteSoldiersStrategy : Strategy
{
@@ -52,4 +51,4 @@ namespace Managing.Application.Strategies
}
}
}
}
}