Add synthApi (#27)

* Add synthApi

* Put confidence for Synth proba

* Update the code

* Update readme

* Fix bootstraping

* fix github build

* Update the endpoints for scenario

* Add scenario and update backtest modal

* Update bot modal

* Update interfaces for synth

* add synth to backtest

* Add Kelly criterion and better signal

* Update signal confidence

* update doc

* save leaderboard and prediction

* Update nswag to generate ApiClient in the correct path

* Unify the trading modal

* Save miner and prediction

* Update messaging and block new signal until position not close when flipping off

* Rename strategies to indicators

* Update doc

* Update chart + add signal name

* Fix signal direction

* Update docker webui

* remove crypto npm

* Clean
This commit is contained in:
Oda
2025-07-03 00:13:42 +07:00
committed by GitHub
parent 453806356d
commit a547c4a040
103 changed files with 9916 additions and 810 deletions

View File

@@ -18,5 +18,6 @@ namespace Managing.Infrastructure.Databases.MongoDb.Collections
public IndicatorType Type { get; set; }
public SignalType SignalType { get; set; }
public UserDto User { get; set; }
public string IndicatorName { get; set; }
}
}

View File

@@ -0,0 +1,42 @@
using Managing.Infrastructure.Databases.MongoDb.Attributes;
using Managing.Infrastructure.Databases.MongoDb.Configurations;
namespace Managing.Infrastructure.Databases.MongoDb.Collections;
/// <summary>
/// MongoDB DTO for storing Synth miners leaderboard data
/// </summary>
[BsonCollection("SynthMinersLeaderboard")]
public class SynthMinersLeaderboardDto : Document
{
/// <summary>
/// Asset symbol (e.g., "BTC", "ETH")
/// </summary>
public string Asset { get; set; }
/// <summary>
/// Time increment used for this leaderboard data
/// </summary>
public int TimeIncrement { get; set; }
/// <summary>
/// Signal date for which this leaderboard was retrieved (for backtests)
/// Null for live trading data
/// </summary>
public DateTime? SignalDate { get; set; }
/// <summary>
/// Whether this is backtest data or live data
/// </summary>
public bool IsBacktest { get; set; }
/// <summary>
/// Serialized JSON of miners list
/// </summary>
public string MinersData { get; set; }
/// <summary>
/// Cache key for quick lookup
/// </summary>
public string CacheKey { get; set; }
}

View File

@@ -0,0 +1,57 @@
using Managing.Infrastructure.Databases.MongoDb.Attributes;
using Managing.Infrastructure.Databases.MongoDb.Configurations;
namespace Managing.Infrastructure.Databases.MongoDb.Collections;
/// <summary>
/// MongoDB DTO for storing Synth miners predictions data
/// </summary>
[BsonCollection("SynthMinersPredictions")]
public class SynthMinersPredictionsDto : Document
{
/// <summary>
/// Asset symbol (e.g., "BTC", "ETH")
/// </summary>
public string Asset { get; set; }
/// <summary>
/// Time increment used for these predictions
/// </summary>
public int TimeIncrement { get; set; }
/// <summary>
/// Time length (horizon) for these predictions in seconds
/// </summary>
public int TimeLength { get; set; }
/// <summary>
/// Signal date for which these predictions were retrieved (for backtests)
/// Null for live trading data
/// </summary>
public DateTime? SignalDate { get; set; }
/// <summary>
/// Whether this is backtest data or live data
/// </summary>
public bool IsBacktest { get; set; }
/// <summary>
/// Serialized JSON of miner UIDs list
/// </summary>
public string MinerUidsData { get; set; }
/// <summary>
/// Serialized JSON of predictions data
/// </summary>
public string PredictionsData { get; set; }
/// <summary>
/// When this prediction data was fetched from the API
/// </summary>
public DateTime FetchedAt { get; set; }
/// <summary>
/// Cache key for quick lookup
/// </summary>
public string CacheKey { get; set; }
}

View File

@@ -0,0 +1,52 @@
using Managing.Infrastructure.Databases.MongoDb.Attributes;
using Managing.Infrastructure.Databases.MongoDb.Configurations;
namespace Managing.Infrastructure.Databases.MongoDb.Collections;
/// <summary>
/// MongoDB DTO for storing individual Synth miner prediction data
/// </summary>
[BsonCollection("SynthPredictions")]
public class SynthPredictionDto : Document
{
/// <summary>
/// Asset symbol (e.g., "BTC", "ETH")
/// </summary>
public string Asset { get; set; }
/// <summary>
/// Miner UID that provided this prediction
/// </summary>
public int MinerUid { get; set; }
/// <summary>
/// Time increment used for this prediction
/// </summary>
public int TimeIncrement { get; set; }
/// <summary>
/// Time length (horizon) for this prediction in seconds
/// </summary>
public int TimeLength { get; set; }
/// <summary>
/// Signal date for which this prediction was retrieved (for backtests)
/// Null for live trading data
/// </summary>
public DateTime? SignalDate { get; set; }
/// <summary>
/// Whether this is backtest data or live data
/// </summary>
public bool IsBacktest { get; set; }
/// <summary>
/// Serialized JSON of the prediction data
/// </summary>
public string PredictionData { get; set; }
/// <summary>
/// Cache key for quick lookup
/// </summary>
public string CacheKey { get; set; }
}

View File

@@ -1,4 +1,5 @@
using Managing.Domain.Accounts;
using System.Text.Json;
using Managing.Domain.Accounts;
using Managing.Domain.Backtests;
using Managing.Domain.Bots;
using Managing.Domain.Candles;
@@ -6,6 +7,7 @@ using Managing.Domain.MoneyManagements;
using Managing.Domain.Scenarios;
using Managing.Domain.Statistics;
using Managing.Domain.Strategies;
using Managing.Domain.Synth.Models;
using Managing.Domain.Trades;
using Managing.Domain.Users;
using Managing.Domain.Workers;
@@ -371,7 +373,8 @@ public static class MongoMappers
Status = signal.Status,
Timeframe = signal.Timeframe,
Type = signal.IndicatorType,
User = signal.User != null ? Map(signal.User) : null
User = signal.User != null ? Map(signal.User) : null,
IndicatorName = signal.IndicatorName
};
}
@@ -387,6 +390,7 @@ public static class MongoMappers
TradingExchanges.Binance, //TODO FIXME When the signal status is modified from controller
bSignal.Type,
bSignal.SignalType,
bSignal.IndicatorName,
bSignal.User != null ? Map(bSignal.User) : null)
{
Status = bSignal.Status
@@ -744,7 +748,6 @@ public static class MongoMappers
{
User = Map(bot.User),
Identifier = bot.Identifier,
BotType = bot.BotType,
Data = bot.Data,
LastStatus = bot.LastStatus
};
@@ -758,7 +761,6 @@ public static class MongoMappers
{
User = Map(b.User),
Identifier = b.Identifier,
BotType = b.BotType,
Data = b.Data,
LastStatus = b.LastStatus
};
@@ -792,4 +794,143 @@ public static class MongoMappers
Direction = fundingRate.Direction
};
}
#region Synth
/// <summary>
/// Maps domain SynthMinersLeaderboard to MongoDB DTO
/// </summary>
internal static SynthMinersLeaderboardDto Map(SynthMinersLeaderboard leaderboard)
{
if (leaderboard == null) return null;
return new SynthMinersLeaderboardDto
{
Asset = leaderboard.Asset,
TimeIncrement = leaderboard.TimeIncrement,
SignalDate = leaderboard.SignalDate,
IsBacktest = leaderboard.IsBacktest,
MinersData = JsonSerializer.Serialize(leaderboard.Miners),
CacheKey = leaderboard.GetCacheKey()
};
}
/// <summary>
/// Maps MongoDB DTO to domain SynthMinersLeaderboard
/// </summary>
internal static SynthMinersLeaderboard Map(SynthMinersLeaderboardDto dto)
{
if (dto == null) return null;
var miners = string.IsNullOrEmpty(dto.MinersData)
? new List<MinerInfo>()
: JsonSerializer.Deserialize<List<MinerInfo>>(dto.MinersData) ?? new List<MinerInfo>();
return new SynthMinersLeaderboard
{
Id = dto.Id.ToString(),
Asset = dto.Asset,
TimeIncrement = dto.TimeIncrement,
SignalDate = dto.SignalDate,
IsBacktest = dto.IsBacktest,
Miners = miners,
CreatedAt = dto.CreatedAt
};
}
/// <summary>
/// Maps domain SynthMinersPredictions to MongoDB DTO
/// </summary>
internal static SynthMinersPredictionsDto Map(SynthMinersPredictions predictions)
{
if (predictions == null) return null;
return new SynthMinersPredictionsDto
{
Asset = predictions.Asset,
TimeIncrement = predictions.TimeIncrement,
TimeLength = predictions.TimeLength,
SignalDate = predictions.SignalDate,
IsBacktest = predictions.IsBacktest,
MinerUidsData = JsonSerializer.Serialize(predictions.MinerUids),
PredictionsData = JsonSerializer.Serialize(predictions.Predictions),
CacheKey = predictions.GetCacheKey()
};
}
/// <summary>
/// Maps MongoDB DTO to domain SynthMinersPredictions
/// </summary>
internal static SynthMinersPredictions Map(SynthMinersPredictionsDto dto)
{
if (dto == null) return null;
var minerUids = string.IsNullOrEmpty(dto.MinerUidsData)
? new List<int>()
: JsonSerializer.Deserialize<List<int>>(dto.MinerUidsData) ?? new List<int>();
var predictions = string.IsNullOrEmpty(dto.PredictionsData)
? new List<MinerPrediction>()
: JsonSerializer.Deserialize<List<MinerPrediction>>(dto.PredictionsData) ?? new List<MinerPrediction>();
return new SynthMinersPredictions
{
Id = dto.Id.ToString(),
Asset = dto.Asset,
TimeIncrement = dto.TimeIncrement,
TimeLength = dto.TimeLength,
SignalDate = dto.SignalDate,
IsBacktest = dto.IsBacktest,
MinerUids = minerUids,
Predictions = predictions,
CreatedAt = dto.CreatedAt
};
}
/// <summary>
/// Maps domain SynthPrediction to MongoDB DTO
/// </summary>
internal static SynthPredictionDto Map(SynthPrediction prediction)
{
if (prediction == null) return null;
return new SynthPredictionDto
{
Asset = prediction.Asset,
MinerUid = prediction.MinerUid,
TimeIncrement = prediction.TimeIncrement,
TimeLength = prediction.TimeLength,
SignalDate = prediction.SignalDate,
IsBacktest = prediction.IsBacktest,
PredictionData = JsonSerializer.Serialize(prediction.Prediction),
CacheKey = prediction.GetCacheKey()
};
}
/// <summary>
/// Maps MongoDB DTO to domain SynthPrediction
/// </summary>
internal static SynthPrediction Map(SynthPredictionDto dto)
{
if (dto == null) return null;
var prediction = string.IsNullOrEmpty(dto.PredictionData)
? null
: JsonSerializer.Deserialize<MinerPrediction>(dto.PredictionData);
return new SynthPrediction
{
Id = dto.Id.ToString(),
Asset = dto.Asset,
MinerUid = dto.MinerUid,
TimeIncrement = dto.TimeIncrement,
TimeLength = dto.TimeLength,
SignalDate = dto.SignalDate,
IsBacktest = dto.IsBacktest,
Prediction = prediction,
CreatedAt = dto.CreatedAt
};
}
#endregion
}