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:
@@ -1,9 +1,12 @@
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Api.Models.Requests;
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Application.Hubs;
|
||||
using Managing.Domain.Backtests;
|
||||
using Managing.Domain.Bots;
|
||||
using Managing.Domain.MoneyManagements;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Managing.Domain.Strategies;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
@@ -123,7 +126,7 @@ public class BacktestController : BaseController
|
||||
return BadRequest("Either scenario name or scenario object is required");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(request.MoneyManagementName) && request.MoneyManagement == null)
|
||||
if (string.IsNullOrEmpty(request.Config.MoneyManagementName) && request.Config.MoneyManagement == null)
|
||||
{
|
||||
return BadRequest("Either money management name or money management object is required");
|
||||
}
|
||||
@@ -136,26 +139,58 @@ public class BacktestController : BaseController
|
||||
|
||||
// Get money management
|
||||
MoneyManagement moneyManagement;
|
||||
if (!string.IsNullOrEmpty(request.MoneyManagementName))
|
||||
if (!string.IsNullOrEmpty(request.Config.MoneyManagementName))
|
||||
{
|
||||
moneyManagement = await _moneyManagementService.GetMoneyMangement(user, request.MoneyManagementName);
|
||||
moneyManagement =
|
||||
await _moneyManagementService.GetMoneyMangement(user, request.Config.MoneyManagementName);
|
||||
if (moneyManagement == null)
|
||||
return BadRequest("Money management not found");
|
||||
}
|
||||
else
|
||||
{
|
||||
moneyManagement = request.MoneyManagement;
|
||||
moneyManagement = Map(request.Config.MoneyManagement);
|
||||
moneyManagement?.FormatPercentage();
|
||||
}
|
||||
|
||||
// Update config with money management - TradingBot will handle scenario loading
|
||||
// Handle scenario - either from ScenarioRequest or ScenarioName
|
||||
Scenario scenario = null;
|
||||
if (request.Config.Scenario != null)
|
||||
{
|
||||
// Convert ScenarioRequest to Scenario domain object
|
||||
scenario = new Scenario(request.Config.Scenario.Name, request.Config.Scenario.LoopbackPeriod)
|
||||
{
|
||||
User = user
|
||||
};
|
||||
|
||||
// Convert IndicatorRequest objects to Indicator domain objects
|
||||
foreach (var indicatorRequest in request.Config.Scenario.Indicators)
|
||||
{
|
||||
var indicator = new Indicator(indicatorRequest.Name, indicatorRequest.Type)
|
||||
{
|
||||
SignalType = indicatorRequest.SignalType,
|
||||
MinimumHistory = indicatorRequest.MinimumHistory,
|
||||
Period = indicatorRequest.Period,
|
||||
FastPeriods = indicatorRequest.FastPeriods,
|
||||
SlowPeriods = indicatorRequest.SlowPeriods,
|
||||
SignalPeriods = indicatorRequest.SignalPeriods,
|
||||
Multiplier = indicatorRequest.Multiplier,
|
||||
SmoothPeriods = indicatorRequest.SmoothPeriods,
|
||||
StochPeriods = indicatorRequest.StochPeriods,
|
||||
CyclePeriods = indicatorRequest.CyclePeriods,
|
||||
User = user
|
||||
};
|
||||
scenario.AddIndicator(indicator);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert TradingBotConfigRequest to TradingBotConfig for backtest
|
||||
var backtestConfig = new TradingBotConfig
|
||||
{
|
||||
AccountName = request.Config.AccountName,
|
||||
MoneyManagement = moneyManagement,
|
||||
Ticker = request.Config.Ticker,
|
||||
ScenarioName = request.Config.ScenarioName,
|
||||
Scenario = request.Config.Scenario,
|
||||
Scenario = scenario, // Use the converted scenario object
|
||||
Timeframe = request.Config.Timeframe,
|
||||
IsForWatchingOnly = request.WatchOnly,
|
||||
BotTradingBalance = request.Balance,
|
||||
@@ -165,10 +200,14 @@ public class BacktestController : BaseController
|
||||
MaxLossStreak = request.Config.MaxLossStreak,
|
||||
MaxPositionTimeHours = request.Config.MaxPositionTimeHours,
|
||||
FlipOnlyWhenInProfit = request.Config.FlipOnlyWhenInProfit,
|
||||
FlipPosition = request.Config.FlipPosition,
|
||||
FlipPosition = request.Config.BotType == BotType.FlippingBot, // Computed based on BotType
|
||||
Name = request.Config.Name ??
|
||||
$"Backtest-{request.Config.ScenarioName ?? request.Config.Scenario?.Name ?? "Custom"}-{DateTime.UtcNow:yyyyMMdd-HHmmss}",
|
||||
CloseEarlyWhenProfitable = request.Config.CloseEarlyWhenProfitable,
|
||||
UseSynthApi = request.Config.UseSynthApi,
|
||||
UseForPositionSizing = request.Config.UseForPositionSizing,
|
||||
UseForSignalFiltering = request.Config.UseForSignalFiltering,
|
||||
UseForDynamicStopLoss = request.Config.UseForDynamicStopLoss
|
||||
};
|
||||
|
||||
switch (request.Config.BotType)
|
||||
@@ -208,6 +247,18 @@ public class BacktestController : BaseController
|
||||
await _hubContext.Clients.All.SendAsync("BacktestsSubscription", backtesting);
|
||||
}
|
||||
}
|
||||
|
||||
public MoneyManagement Map(MoneyManagementRequest moneyManagementRequest)
|
||||
{
|
||||
return new MoneyManagement
|
||||
{
|
||||
Name = moneyManagementRequest.Name,
|
||||
StopLoss = moneyManagementRequest.StopLoss,
|
||||
TakeProfit = moneyManagementRequest.TakeProfit,
|
||||
Leverage = moneyManagementRequest.Leverage,
|
||||
Timeframe = moneyManagementRequest.Timeframe
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -216,9 +267,9 @@ public class BacktestController : BaseController
|
||||
public class RunBacktestRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The trading bot configuration to use for the backtest
|
||||
/// The trading bot configuration request to use for the backtest
|
||||
/// </summary>
|
||||
public TradingBotConfig Config { get; set; }
|
||||
public TradingBotConfigRequest Config { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date for the backtest
|
||||
@@ -244,14 +295,4 @@ public class RunBacktestRequest
|
||||
/// Whether to save the backtest results
|
||||
/// </summary>
|
||||
public bool Save { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the money management to use (optional if MoneyManagement is provided)
|
||||
/// </summary>
|
||||
public string? MoneyManagementName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The money management details (optional if MoneyManagementName is provided)
|
||||
/// </summary>
|
||||
public MoneyManagement? MoneyManagement { get; set; }
|
||||
}
|
||||
@@ -30,6 +30,9 @@ public abstract class BaseController : ControllerBase
|
||||
|
||||
throw new Exception("User not found for this token");
|
||||
}
|
||||
|
||||
throw new Exception("Not identity assigned to this token");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Managing.Api.Models.Requests;
|
||||
using Managing.Api.Models.Responses;
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
@@ -7,6 +7,8 @@ using Managing.Application.ManageBot.Commands;
|
||||
using Managing.Common;
|
||||
using Managing.Domain.Bots;
|
||||
using Managing.Domain.MoneyManagements;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Trades;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@@ -117,24 +119,37 @@ public class BotController : BaseController
|
||||
return Forbid("You don't have permission to start a bot with this account");
|
||||
}
|
||||
|
||||
// Trigger error if money management is not provided
|
||||
if (string.IsNullOrEmpty(request.MoneyManagementName) && request.Config.MoneyManagement == null)
|
||||
// Validate that either money management name or object is provided
|
||||
if (string.IsNullOrEmpty(request.Config.MoneyManagementName) && request.Config.MoneyManagement == null)
|
||||
{
|
||||
return BadRequest("Money management name or money management object is required");
|
||||
return BadRequest("Either money management name or money management object is required");
|
||||
}
|
||||
|
||||
var user = await GetUser();
|
||||
|
||||
// Get money management if name is provided
|
||||
MoneyManagement moneyManagement = request.Config.MoneyManagement;
|
||||
if (!string.IsNullOrEmpty(request.MoneyManagementName))
|
||||
|
||||
// Get money management - either by name lookup or use provided object
|
||||
MoneyManagement moneyManagement;
|
||||
if (!string.IsNullOrEmpty(request.Config.MoneyManagementName))
|
||||
{
|
||||
moneyManagement = await _moneyManagementService.GetMoneyMangement(user, request.MoneyManagementName);
|
||||
moneyManagement =
|
||||
await _moneyManagementService.GetMoneyMangement(user, request.Config.MoneyManagementName);
|
||||
if (moneyManagement == null)
|
||||
{
|
||||
return BadRequest("Money management not found");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
moneyManagement = Map(request.Config.MoneyManagement);
|
||||
// Format percentage values if using custom money management
|
||||
moneyManagement?.FormatPercentage();
|
||||
|
||||
// Ensure user is set for custom money management
|
||||
if (moneyManagement != null)
|
||||
{
|
||||
moneyManagement.User = user;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate initialTradingBalance
|
||||
if (request.Config.BotTradingBalance <= Constants.GMX.Config.MinimumPositionAmount)
|
||||
@@ -167,13 +182,45 @@ public class BotController : BaseController
|
||||
return BadRequest("CloseEarlyWhenProfitable can only be enabled when MaxPositionTimeHours is set");
|
||||
}
|
||||
|
||||
// Update the config with final money management
|
||||
// Handle scenario - either from ScenarioRequest or ScenarioName
|
||||
Scenario scenario = null;
|
||||
if (request.Config.Scenario != null)
|
||||
{
|
||||
// Convert ScenarioRequest to Scenario domain object
|
||||
scenario = new Scenario(request.Config.Scenario.Name, request.Config.Scenario.LoopbackPeriod)
|
||||
{
|
||||
User = user
|
||||
};
|
||||
|
||||
// Convert IndicatorRequest objects to Indicator domain objects
|
||||
foreach (var indicatorRequest in request.Config.Scenario.Indicators)
|
||||
{
|
||||
var indicator = new Indicator(indicatorRequest.Name, indicatorRequest.Type)
|
||||
{
|
||||
SignalType = indicatorRequest.SignalType,
|
||||
MinimumHistory = indicatorRequest.MinimumHistory,
|
||||
Period = indicatorRequest.Period,
|
||||
FastPeriods = indicatorRequest.FastPeriods,
|
||||
SlowPeriods = indicatorRequest.SlowPeriods,
|
||||
SignalPeriods = indicatorRequest.SignalPeriods,
|
||||
Multiplier = indicatorRequest.Multiplier,
|
||||
SmoothPeriods = indicatorRequest.SmoothPeriods,
|
||||
StochPeriods = indicatorRequest.StochPeriods,
|
||||
CyclePeriods = indicatorRequest.CyclePeriods,
|
||||
User = user
|
||||
};
|
||||
scenario.AddIndicator(indicator);
|
||||
}
|
||||
}
|
||||
|
||||
// Map the request to the full TradingBotConfig
|
||||
var config = new TradingBotConfig
|
||||
{
|
||||
AccountName = request.Config.AccountName,
|
||||
MoneyManagement = moneyManagement,
|
||||
Ticker = request.Config.Ticker,
|
||||
ScenarioName = request.Config.ScenarioName,
|
||||
Scenario = scenario, // Use the converted scenario object
|
||||
ScenarioName = request.Config.ScenarioName, // Fallback to scenario name if scenario object not provided
|
||||
Timeframe = request.Config.Timeframe,
|
||||
IsForWatchingOnly = request.Config.IsForWatchingOnly,
|
||||
BotTradingBalance = request.Config.BotTradingBalance,
|
||||
@@ -182,10 +229,15 @@ public class BotController : BaseController
|
||||
MaxLossStreak = request.Config.MaxLossStreak,
|
||||
MaxPositionTimeHours = request.Config.MaxPositionTimeHours,
|
||||
FlipOnlyWhenInProfit = request.Config.FlipOnlyWhenInProfit,
|
||||
CloseEarlyWhenProfitable = request.Config.CloseEarlyWhenProfitable,
|
||||
UseSynthApi = request.Config.UseSynthApi,
|
||||
UseForPositionSizing = request.Config.UseForPositionSizing,
|
||||
UseForSignalFiltering = request.Config.UseForSignalFiltering,
|
||||
UseForDynamicStopLoss = request.Config.UseForDynamicStopLoss,
|
||||
// Set computed/default properties
|
||||
IsForBacktest = false,
|
||||
FlipPosition = request.Config.BotType == BotType.FlippingBot,
|
||||
Name = request.Config.Name,
|
||||
CloseEarlyWhenProfitable = request.Config.CloseEarlyWhenProfitable
|
||||
Name = request.Config.Name
|
||||
};
|
||||
|
||||
var result = await _mediator.Send(new StartBotCommand(config, request.Config.Name, user));
|
||||
@@ -200,6 +252,7 @@ public class BotController : BaseController
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stops a bot specified by type and name.
|
||||
/// </summary>
|
||||
@@ -614,7 +667,7 @@ public class BotController : BaseController
|
||||
// Get the existing bot to ensure it exists and get current config
|
||||
var bots = _botService.GetActiveBots();
|
||||
var existingBot = bots.FirstOrDefault(b => b.Identifier == request.Identifier);
|
||||
|
||||
|
||||
if (existingBot == null)
|
||||
{
|
||||
return NotFound($"Bot with identifier '{request.Identifier}' not found");
|
||||
@@ -630,9 +683,9 @@ public class BotController : BaseController
|
||||
}
|
||||
|
||||
// If the bot name is being changed, check for conflicts
|
||||
var isNameChanging = !string.IsNullOrEmpty(request.Config.Name) &&
|
||||
var isNameChanging = !string.IsNullOrEmpty(request.Config.Name) &&
|
||||
request.Config.Name != request.Identifier;
|
||||
|
||||
|
||||
if (isNameChanging)
|
||||
{
|
||||
// Check if new name already exists
|
||||
@@ -643,31 +696,36 @@ public class BotController : BaseController
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the money management if provided
|
||||
if (request.Config.MoneyManagement != null)
|
||||
// Validate and get the money management
|
||||
MoneyManagement moneyManagement = null;
|
||||
if (!string.IsNullOrEmpty(request.MoneyManagementName))
|
||||
{
|
||||
// Check if the money management belongs to the user
|
||||
var userMoneyManagement = await _moneyManagementService.GetMoneyMangement(user, request.Config.MoneyManagement.Name);
|
||||
if (userMoneyManagement != null && userMoneyManagement.User?.Name != user.Name)
|
||||
{
|
||||
return Forbid("You don't have permission to use this money management");
|
||||
}
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(request.MoneyManagementName))
|
||||
{
|
||||
// If MoneyManagement is null but MoneyManagementName is provided, load it
|
||||
var moneyManagement = await _moneyManagementService.GetMoneyMangement(user, request.MoneyManagementName);
|
||||
// Load money management by name
|
||||
moneyManagement = await _moneyManagementService.GetMoneyMangement(user, request.MoneyManagementName);
|
||||
if (moneyManagement == null)
|
||||
{
|
||||
return BadRequest($"Money management '{request.MoneyManagementName}' not found");
|
||||
}
|
||||
|
||||
|
||||
if (moneyManagement.User?.Name != user.Name)
|
||||
{
|
||||
return Forbid("You don't have permission to use this money management");
|
||||
}
|
||||
|
||||
request.Config.MoneyManagement = moneyManagement;
|
||||
}
|
||||
else if (request.MoneyManagement != null)
|
||||
{
|
||||
// Use provided money management object
|
||||
moneyManagement = request.MoneyManagement;
|
||||
// Format percentage values if using custom money management
|
||||
moneyManagement.FormatPercentage();
|
||||
|
||||
// Ensure user is set for custom money management
|
||||
moneyManagement.User = user;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use existing bot's money management if no new one is provided
|
||||
moneyManagement = existingBot.Config.MoneyManagement;
|
||||
}
|
||||
|
||||
// Validate CloseEarlyWhenProfitable requires MaxPositionTimeHours
|
||||
@@ -676,27 +734,85 @@ public class BotController : BaseController
|
||||
return BadRequest("CloseEarlyWhenProfitable requires MaxPositionTimeHours to be set");
|
||||
}
|
||||
|
||||
// Handle scenario - either from ScenarioRequest or ScenarioName
|
||||
Scenario scenarioForUpdate = null;
|
||||
if (request.Config.Scenario != null)
|
||||
{
|
||||
// Convert ScenarioRequest to Scenario domain object
|
||||
scenarioForUpdate = new Scenario(request.Config.Scenario.Name, request.Config.Scenario.LoopbackPeriod)
|
||||
{
|
||||
User = user
|
||||
};
|
||||
|
||||
// Convert IndicatorRequest objects to Indicator domain objects
|
||||
foreach (var indicatorRequest in request.Config.Scenario.Indicators)
|
||||
{
|
||||
var indicator = new Indicator(indicatorRequest.Name, indicatorRequest.Type)
|
||||
{
|
||||
SignalType = indicatorRequest.SignalType,
|
||||
MinimumHistory = indicatorRequest.MinimumHistory,
|
||||
Period = indicatorRequest.Period,
|
||||
FastPeriods = indicatorRequest.FastPeriods,
|
||||
SlowPeriods = indicatorRequest.SlowPeriods,
|
||||
SignalPeriods = indicatorRequest.SignalPeriods,
|
||||
Multiplier = indicatorRequest.Multiplier,
|
||||
SmoothPeriods = indicatorRequest.SmoothPeriods,
|
||||
StochPeriods = indicatorRequest.StochPeriods,
|
||||
CyclePeriods = indicatorRequest.CyclePeriods,
|
||||
User = user
|
||||
};
|
||||
scenarioForUpdate.AddIndicator(indicator);
|
||||
}
|
||||
}
|
||||
|
||||
// Map the request to the full TradingBotConfig
|
||||
var updatedConfig = new TradingBotConfig
|
||||
{
|
||||
AccountName = request.Config.AccountName,
|
||||
MoneyManagement = moneyManagement,
|
||||
Ticker = request.Config.Ticker,
|
||||
Scenario = scenarioForUpdate, // Use the converted scenario object
|
||||
ScenarioName = request.Config.ScenarioName, // Fallback to scenario name if scenario object not provided
|
||||
Timeframe = request.Config.Timeframe,
|
||||
IsForWatchingOnly = request.Config.IsForWatchingOnly,
|
||||
BotTradingBalance = request.Config.BotTradingBalance,
|
||||
BotType = request.Config.BotType,
|
||||
CooldownPeriod = request.Config.CooldownPeriod,
|
||||
MaxLossStreak = request.Config.MaxLossStreak,
|
||||
MaxPositionTimeHours = request.Config.MaxPositionTimeHours,
|
||||
FlipOnlyWhenInProfit = request.Config.FlipOnlyWhenInProfit,
|
||||
CloseEarlyWhenProfitable = request.Config.CloseEarlyWhenProfitable,
|
||||
UseSynthApi = request.Config.UseSynthApi,
|
||||
UseForPositionSizing = request.Config.UseForPositionSizing,
|
||||
UseForSignalFiltering = request.Config.UseForSignalFiltering,
|
||||
UseForDynamicStopLoss = request.Config.UseForDynamicStopLoss,
|
||||
// Set computed/default properties
|
||||
IsForBacktest = false,
|
||||
FlipPosition = request.Config.BotType == BotType.FlippingBot,
|
||||
Name = request.Config.Name
|
||||
};
|
||||
|
||||
// Update the bot configuration using the enhanced method
|
||||
var success = await _botService.UpdateBotConfiguration(request.Identifier, request.Config);
|
||||
|
||||
var success = await _botService.UpdateBotConfiguration(request.Identifier, updatedConfig);
|
||||
|
||||
if (success)
|
||||
{
|
||||
var finalBotName = isNameChanging ? request.Config.Name : request.Identifier;
|
||||
|
||||
|
||||
await _hubContext.Clients.All.SendAsync("SendNotification",
|
||||
$"Bot {finalBotName} configuration updated successfully by {user.Name}." +
|
||||
(isNameChanging ? $" (renamed from {request.Identifier})" : ""), "Info");
|
||||
|
||||
|
||||
await NotifyBotSubscriberAsync();
|
||||
|
||||
return Ok(isNameChanging
|
||||
|
||||
return Ok(isNameChanging
|
||||
? $"Bot configuration updated successfully and renamed to '{request.Config.Name}'"
|
||||
: "Bot configuration updated successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
return BadRequest("Failed to update bot configuration. " +
|
||||
(isNameChanging ? "The new name might already be in use." : ""));
|
||||
(isNameChanging ? "The new name might already be in use." : ""));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -705,6 +821,18 @@ public class BotController : BaseController
|
||||
return StatusCode(500, $"Error updating bot configuration: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public MoneyManagement Map(MoneyManagementRequest moneyManagementRequest)
|
||||
{
|
||||
return new MoneyManagement
|
||||
{
|
||||
Name = moneyManagementRequest.Name,
|
||||
StopLoss = moneyManagementRequest.StopLoss,
|
||||
TakeProfit = moneyManagementRequest.TakeProfit,
|
||||
Leverage = moneyManagementRequest.Leverage,
|
||||
Timeframe = moneyManagementRequest.Timeframe
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -745,35 +873,7 @@ public class ClosePositionRequest
|
||||
public class StartBotRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The trading bot configuration
|
||||
/// The trading bot configuration request with primary properties
|
||||
/// </summary>
|
||||
public TradingBotConfig Config { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional money management name (if not included in Config.MoneyManagement)
|
||||
/// </summary>
|
||||
public string? MoneyManagementName { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request model for updating bot configuration
|
||||
/// </summary>
|
||||
public class UpdateBotConfigRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique identifier of the bot to update
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Identifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The new trading bot configuration
|
||||
/// </summary>
|
||||
[Required]
|
||||
public TradingBotConfig Config { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional: Money management name to load if Config.MoneyManagement is null
|
||||
/// </summary>
|
||||
public string? MoneyManagementName { get; set; }
|
||||
public TradingBotConfigRequest Config { get; set; }
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Api.Models.Responses;
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Managing.Domain.Strategies;
|
||||
@@ -39,10 +40,12 @@ public class ScenarioController : BaseController
|
||||
/// </summary>
|
||||
/// <returns>A list of scenarios.</returns>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<IEnumerable<Scenario>>> GetScenarios()
|
||||
public async Task<ActionResult<IEnumerable<ScenarioViewModel>>> GetScenarios()
|
||||
{
|
||||
var user = await GetUser();
|
||||
return Ok(_scenarioService.GetScenariosByUser(user));
|
||||
var scenarios = _scenarioService.GetScenariosByUser(user);
|
||||
var scenarioViewModels = scenarios.Select(MapToScenarioViewModel);
|
||||
return Ok(scenarioViewModels);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -52,11 +55,13 @@ public class ScenarioController : BaseController
|
||||
/// <param name="strategies">A list of strategy names to include in the scenario.</param>
|
||||
/// <returns>The created scenario.</returns>
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<Scenario>> CreateScenario(string name, List<string> strategies,
|
||||
public async Task<ActionResult<ScenarioViewModel>> CreateScenario(string name, List<string> strategies,
|
||||
int? loopbackPeriod = null)
|
||||
{
|
||||
var user = await GetUser();
|
||||
return Ok(_scenarioService.CreateScenarioForUser(user, name, strategies, loopbackPeriod));
|
||||
var scenario = _scenarioService.CreateScenarioForUser(user, name, strategies, loopbackPeriod);
|
||||
var scenarioViewModel = MapToScenarioViewModel(scenario);
|
||||
return Ok(scenarioViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -85,10 +90,12 @@ public class ScenarioController : BaseController
|
||||
/// <returns>A list of strategies.</returns>
|
||||
[HttpGet]
|
||||
[Route("indicator")]
|
||||
public async Task<ActionResult<IEnumerable<Indicator>>> GetIndicators()
|
||||
public async Task<ActionResult<IEnumerable<IndicatorViewModel>>> GetIndicators()
|
||||
{
|
||||
var user = await GetUser();
|
||||
return Ok(_scenarioService.GetIndicatorsByUser(user));
|
||||
var indicators = _scenarioService.GetIndicatorsByUser(user);
|
||||
var indicatorViewModels = indicators.Select(MapToIndicatorViewModel);
|
||||
return Ok(indicatorViewModels);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -107,7 +114,7 @@ public class ScenarioController : BaseController
|
||||
/// <returns>The created indicator.</returns>
|
||||
[HttpPost]
|
||||
[Route("indicator")]
|
||||
public async Task<ActionResult<Indicator>> CreateIndicator(
|
||||
public async Task<ActionResult<IndicatorViewModel>> CreateIndicator(
|
||||
IndicatorType indicatorType,
|
||||
string name,
|
||||
int? period = null,
|
||||
@@ -120,7 +127,7 @@ public class ScenarioController : BaseController
|
||||
int? cyclePeriods = null)
|
||||
{
|
||||
var user = await GetUser();
|
||||
return Ok(_scenarioService.CreateIndicatorForUser(
|
||||
var indicator = _scenarioService.CreateIndicatorForUser(
|
||||
user,
|
||||
indicatorType,
|
||||
name,
|
||||
@@ -131,7 +138,9 @@ public class ScenarioController : BaseController
|
||||
multiplier,
|
||||
stochPeriods,
|
||||
smoothPeriods,
|
||||
cyclePeriods));
|
||||
cyclePeriods);
|
||||
var indicatorViewModel = MapToIndicatorViewModel(indicator);
|
||||
return Ok(indicatorViewModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -176,4 +185,35 @@ public class ScenarioController : BaseController
|
||||
smoothPeriods,
|
||||
cyclePeriods));
|
||||
}
|
||||
|
||||
private static ScenarioViewModel MapToScenarioViewModel(Scenario scenario)
|
||||
{
|
||||
return new ScenarioViewModel
|
||||
{
|
||||
Name = scenario.Name,
|
||||
LoopbackPeriod = scenario.LoopbackPeriod,
|
||||
UserName = scenario.User?.Name,
|
||||
Indicators = scenario.Indicators?.Select(MapToIndicatorViewModel).ToList() ?? new List<IndicatorViewModel>()
|
||||
};
|
||||
}
|
||||
|
||||
private static IndicatorViewModel MapToIndicatorViewModel(Indicator indicator)
|
||||
{
|
||||
return new IndicatorViewModel
|
||||
{
|
||||
Name = indicator.Name,
|
||||
Type = indicator.Type,
|
||||
SignalType = indicator.SignalType,
|
||||
MinimumHistory = indicator.MinimumHistory,
|
||||
Period = indicator.Period,
|
||||
FastPeriods = indicator.FastPeriods,
|
||||
SlowPeriods = indicator.SlowPeriods,
|
||||
SignalPeriods = indicator.SignalPeriods,
|
||||
Multiplier = indicator.Multiplier,
|
||||
SmoothPeriods = indicator.SmoothPeriods,
|
||||
StochPeriods = indicator.StochPeriods,
|
||||
CyclePeriods = indicator.CyclePeriods,
|
||||
UserName = indicator.User?.Name
|
||||
};
|
||||
}
|
||||
}
|
||||
73
src/Managing.Api/Models/Requests/IndicatorRequest.cs
Normal file
73
src/Managing.Api/Models/Requests/IndicatorRequest.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Api.Models.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Request model for indicator configuration without user information
|
||||
/// </summary>
|
||||
public class IndicatorRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the indicator
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of indicator
|
||||
/// </summary>
|
||||
[Required]
|
||||
public IndicatorType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The signal type for this indicator
|
||||
/// </summary>
|
||||
[Required]
|
||||
public SignalType SignalType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Minimum history required for this indicator
|
||||
/// </summary>
|
||||
public int MinimumHistory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Period parameter for the indicator
|
||||
/// </summary>
|
||||
public int? Period { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fast periods parameter for indicators like MACD
|
||||
/// </summary>
|
||||
public int? FastPeriods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Slow periods parameter for indicators like MACD
|
||||
/// </summary>
|
||||
public int? SlowPeriods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Signal periods parameter for indicators like MACD
|
||||
/// </summary>
|
||||
public int? SignalPeriods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Multiplier parameter for indicators like SuperTrend
|
||||
/// </summary>
|
||||
public double? Multiplier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Smooth periods parameter
|
||||
/// </summary>
|
||||
public int? SmoothPeriods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Stochastic periods parameter
|
||||
/// </summary>
|
||||
public int? StochPeriods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cycle periods parameter
|
||||
/// </summary>
|
||||
public int? CyclePeriods { get; set; }
|
||||
}
|
||||
13
src/Managing.Api/Models/Requests/MoneyManagementRequest.cs
Normal file
13
src/Managing.Api/Models/Requests/MoneyManagementRequest.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Managing.Common;
|
||||
|
||||
namespace Managing.Api.Models.Requests;
|
||||
|
||||
public class MoneyManagementRequest
|
||||
{
|
||||
[Required] public string Name { get; set; }
|
||||
[Required] public Enums.Timeframe Timeframe { get; set; }
|
||||
[Required] public decimal StopLoss { get; set; }
|
||||
[Required] public decimal TakeProfit { get; set; }
|
||||
[Required] public decimal Leverage { get; set; }
|
||||
}
|
||||
@@ -1,15 +1,49 @@
|
||||
using static Managing.Common.Enums;
|
||||
using Managing.Domain.MoneyManagements;
|
||||
|
||||
namespace Managing.Api.Models.Requests
|
||||
namespace Managing.Api.Models.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Request model for running a backtest
|
||||
/// </summary>
|
||||
public class RunBacktestRequest
|
||||
{
|
||||
public class RunBacktestRequest
|
||||
{
|
||||
public TradingExchanges Exchange { get; set; }
|
||||
public BotType BotType { get; set; }
|
||||
public Ticker Ticker { get; set; }
|
||||
public Timeframe Timeframe { get; set; }
|
||||
public RiskLevel RiskLevel { get; set; }
|
||||
public bool WatchOnly { get; set; }
|
||||
public int Days { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The trading bot configuration request to use for the backtest
|
||||
/// </summary>
|
||||
public TradingBotConfigRequest Config { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date for the backtest
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end date for the backtest
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The starting balance for the backtest
|
||||
/// </summary>
|
||||
public decimal Balance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to only watch the backtest without executing trades
|
||||
/// </summary>
|
||||
public bool WatchOnly { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to save the backtest results
|
||||
/// </summary>
|
||||
public bool Save { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the money management to use (optional if MoneyManagement is provided)
|
||||
/// </summary>
|
||||
public string? MoneyManagementName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The money management details (optional if MoneyManagementName is provided)
|
||||
/// </summary>
|
||||
public MoneyManagement? MoneyManagement { get; set; }
|
||||
}
|
||||
|
||||
26
src/Managing.Api/Models/Requests/ScenarioRequest.cs
Normal file
26
src/Managing.Api/Models/Requests/ScenarioRequest.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Managing.Api.Models.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Request model for scenario configuration without user information
|
||||
/// </summary>
|
||||
public class ScenarioRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the scenario
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of indicator configurations for this scenario
|
||||
/// </summary>
|
||||
[Required]
|
||||
public List<IndicatorRequest> Indicators { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The loopback period for the scenario
|
||||
/// </summary>
|
||||
public int? LoopbackPeriod { get; set; }
|
||||
}
|
||||
@@ -1,31 +1,16 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Api.Models.Requests
|
||||
{
|
||||
/// <summary>
|
||||
/// Request model for starting a bot
|
||||
/// </summary>
|
||||
public class StartBotRequest
|
||||
{
|
||||
[Required] public BotType BotType { get; set; }
|
||||
[Required] public string BotName { get; set; }
|
||||
[Required] public Ticker Ticker { get; set; }
|
||||
[Required] public Timeframe Timeframe { get; set; }
|
||||
[Required] public bool IsForWatchOnly { get; set; }
|
||||
[Required] public string Scenario { get; set; }
|
||||
[Required] public string AccountName { get; set; }
|
||||
[Required] public string MoneyManagementName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initial trading balance in USD for the bot
|
||||
/// The trading bot configuration request with primary properties
|
||||
/// </summary>
|
||||
[Required]
|
||||
[Range(10.00, double.MaxValue, ErrorMessage = "Initial trading balance must be greater than ten")]
|
||||
public decimal InitialTradingBalance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cooldown period in minutes between trades
|
||||
/// </summary>
|
||||
[Required]
|
||||
[Range(1, 1440, ErrorMessage = "Cooldown period must be between 1 and 1440 minutes (24 hours)")]
|
||||
public decimal CooldownPeriod { get; set; } = 1; // Default to 1 minute if not specified
|
||||
public TradingBotConfigRequest Config { get; set; }
|
||||
}
|
||||
}
|
||||
119
src/Managing.Api/Models/Requests/TradingBotConfigRequest.cs
Normal file
119
src/Managing.Api/Models/Requests/TradingBotConfigRequest.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Api.Models.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Simplified trading bot configuration request with only primary properties
|
||||
/// </summary>
|
||||
public class TradingBotConfigRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The account name to use for trading
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string AccountName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ticker/symbol to trade
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Ticker Ticker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The timeframe for trading decisions
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Timeframe Timeframe { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this bot is for watching only (no actual trading)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public bool IsForWatchingOnly { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The initial trading balance for the bot
|
||||
/// </summary>
|
||||
[Required]
|
||||
public decimal BotTradingBalance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of bot (SimpleBot, ScalpingBot, FlippingBot)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public BotType BotType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name/identifier for this bot
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cooldown period between trades (in candles)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int CooldownPeriod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum consecutive losses before stopping the bot
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int MaxLossStreak { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The scenario configuration (takes precedence over ScenarioName)
|
||||
/// </summary>
|
||||
public ScenarioRequest? Scenario { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The scenario name to load from database (only used when Scenario is not provided)
|
||||
/// </summary>
|
||||
public string? ScenarioName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The money management name to load from database (only used when MoneyManagement is not provided)
|
||||
/// </summary>
|
||||
public string? MoneyManagementName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The money management object to use for the bot
|
||||
/// </summary>
|
||||
public MoneyManagementRequest? MoneyManagement { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum time in hours that a position can remain open before being automatically closed
|
||||
/// </summary>
|
||||
public decimal? MaxPositionTimeHours { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to close positions early when they become profitable
|
||||
/// </summary>
|
||||
public bool CloseEarlyWhenProfitable { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to only flip positions when the current position is in profit
|
||||
/// </summary>
|
||||
public bool FlipOnlyWhenInProfit { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use Synth API for predictions and risk assessment
|
||||
/// </summary>
|
||||
public bool UseSynthApi { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use Synth predictions for position sizing adjustments
|
||||
/// </summary>
|
||||
public bool UseForPositionSizing { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use Synth predictions for signal filtering
|
||||
/// </summary>
|
||||
public bool UseForSignalFiltering { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use Synth predictions for dynamic stop-loss/take-profit adjustments
|
||||
/// </summary>
|
||||
public bool UseForDynamicStopLoss { get; set; } = true;
|
||||
}
|
||||
32
src/Managing.Api/Models/Requests/UpdateBotConfigRequest.cs
Normal file
32
src/Managing.Api/Models/Requests/UpdateBotConfigRequest.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Managing.Domain.MoneyManagements;
|
||||
|
||||
namespace Managing.Api.Models.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Request model for updating bot configuration
|
||||
/// </summary>
|
||||
public class UpdateBotConfigRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique identifier of the bot to update
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Identifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The new trading bot configuration request
|
||||
/// </summary>
|
||||
[Required]
|
||||
public TradingBotConfigRequest Config { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional: Money management name to load from database (if MoneyManagement object is not provided)
|
||||
/// </summary>
|
||||
public string? MoneyManagementName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional: Money management object for custom configurations (takes precedence over MoneyManagementName)
|
||||
/// </summary>
|
||||
public MoneyManagement? MoneyManagement { get; set; }
|
||||
}
|
||||
31
src/Managing.Api/Models/Responses/IndicatorViewModel.cs
Normal file
31
src/Managing.Api/Models/Responses/IndicatorViewModel.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Api.Models.Responses;
|
||||
|
||||
public class IndicatorViewModel
|
||||
{
|
||||
[Required]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public IndicatorType Type { get; set; }
|
||||
|
||||
[Required]
|
||||
public SignalType SignalType { get; set; }
|
||||
|
||||
[Required]
|
||||
public int MinimumHistory { get; set; }
|
||||
|
||||
public int? Period { get; set; }
|
||||
public int? FastPeriods { get; set; }
|
||||
public int? SlowPeriods { get; set; }
|
||||
public int? SignalPeriods { get; set; }
|
||||
public double? Multiplier { get; set; }
|
||||
public int? SmoothPeriods { get; set; }
|
||||
public int? StochPeriods { get; set; }
|
||||
public int? CyclePeriods { get; set; }
|
||||
|
||||
[Required]
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
}
|
||||
17
src/Managing.Api/Models/Responses/ScenarioViewModel.cs
Normal file
17
src/Managing.Api/Models/Responses/ScenarioViewModel.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Managing.Api.Models.Responses;
|
||||
|
||||
public class ScenarioViewModel
|
||||
{
|
||||
[Required]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public List<IndicatorViewModel> Indicators { get; set; } = new();
|
||||
|
||||
public int? LoopbackPeriod { get; set; }
|
||||
|
||||
[Required]
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
}
|
||||
Reference in New Issue
Block a user