Fix bot things 2

This commit is contained in:
2025-02-11 02:06:35 +07:00
parent 898ff85eed
commit d7731dda0e
10 changed files with 164 additions and 121 deletions

View File

@@ -1,5 +1,6 @@
using Managing.Api.Models.Requests; using Managing.Api.Models.Requests;
using Managing.Api.Models.Responses; using Managing.Api.Models.Responses;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services; using Managing.Application.Abstractions.Services;
using Managing.Application.Hubs; using Managing.Application.Hubs;
using Managing.Application.ManageBot.Commands; using Managing.Application.ManageBot.Commands;
@@ -25,6 +26,7 @@ public class BotController : ControllerBase
private readonly ILogger<BotController> _logger; private readonly ILogger<BotController> _logger;
private readonly IHubContext<BotHub> _hubContext; private readonly IHubContext<BotHub> _hubContext;
private readonly IBacktester _backtester; private readonly IBacktester _backtester;
private readonly IBotService _botService;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BotController"/> class. /// Initializes a new instance of the <see cref="BotController"/> class.
@@ -34,12 +36,13 @@ public class BotController : ControllerBase
/// <param name="hubContext">SignalR hub context for real-time communication.</param> /// <param name="hubContext">SignalR hub context for real-time communication.</param>
/// <param name="backtester">Backtester for running backtests on bots.</param> /// <param name="backtester">Backtester for running backtests on bots.</param>
public BotController(ILogger<BotController> logger, IMediator mediator, IHubContext<BotHub> hubContext, public BotController(ILogger<BotController> logger, IMediator mediator, IHubContext<BotHub> hubContext,
IBacktester backtester) IBacktester backtester, IBotService botService)
{ {
_logger = logger; _logger = logger;
_mediator = mediator; _mediator = mediator;
_hubContext = hubContext; _hubContext = hubContext;
_backtester = backtester; _backtester = backtester;
_botService = botService;
} }
/// <summary> /// <summary>
@@ -86,11 +89,8 @@ public class BotController : ControllerBase
[Route("Delete")] [Route("Delete")]
public async Task<ActionResult<bool>> Delete(string botName) public async Task<ActionResult<bool>> Delete(string botName)
{ {
var result = await _mediator.Send(new DeleteBotCommand(botName)); var result = await _botService.DeleteBot(botName);
_logger.LogInformation($"{botName} is now deleted");
await NotifyBotSubscriberAsync(); await NotifyBotSubscriberAsync();
return Ok(result); return Ok(result);
} }

View File

@@ -51,16 +51,19 @@ public class DataController : ControllerBase
/// <summary> /// <summary>
/// Retrieves tickers for a given account and timeframe, utilizing caching to improve performance. /// Retrieves tickers for a given account and timeframe, utilizing caching to improve performance.
/// </summary> /// </summary>
/// <param name="accountName">The name of the account to retrieve tickers for.</param>
/// <param name="timeframe">The timeframe for which to retrieve tickers.</param> /// <param name="timeframe">The timeframe for which to retrieve tickers.</param>
/// <returns>An array of tickers.</returns> /// <returns>An array of tickers.</returns>
[HttpPost("GetTickers")] [HttpPost("GetTickers")]
public async Task<ActionResult<Ticker[]>> GetTickers(string accountName, Timeframe timeframe) public async Task<ActionResult<Ticker[]>> GetTickers(Timeframe timeframe)
{ {
var account = await _accountService.GetAccount(accountName, true, false); var cacheKey = string.Concat(timeframe.ToString());
var cacheKey = string.Concat(accountName, timeframe.ToString()); var tickers = _cacheService.GetValue<List<Ticker>>(cacheKey);
var tickers = _cacheService.GetOrSave(cacheKey,
() => { return _exchangeService.GetTickers(account, timeframe).Result; }, TimeSpan.FromHours(2)); if (tickers == null)
{
tickers = await _exchangeService.GetTickers(timeframe);
_cacheService.SaveValue(cacheKey, tickers, TimeSpan.FromHours(2));
}
return Ok(tickers); return Ok(tickers);
} }

View File

@@ -7,5 +7,5 @@ public interface IBotRepository
Task InsertBotAsync(BotBackup bot); Task InsertBotAsync(BotBackup bot);
IEnumerable<BotBackup> GetBots(); IEnumerable<BotBackup> GetBots();
Task UpdateBackupBot(BotBackup bot); Task UpdateBackupBot(BotBackup bot);
void DeleteBotBackup(string botName); Task DeleteBotBackup(string botName);
} }

View File

@@ -30,7 +30,7 @@ public interface IExchangeService
Task<Trade> OpenStopLoss(Account account, Ticker ticker, TradeDirection originalDirection, decimal stopLossPrice, Task<Trade> OpenStopLoss(Account account, Ticker ticker, TradeDirection originalDirection, decimal stopLossPrice,
decimal quantity, bool isForPaperTrading = false, DateTime? currentDate = null); decimal quantity, bool isForPaperTrading = false, DateTime? currentDate = null);
Task<List<Ticker>> GetTickers(Account account, Timeframe timeframe); Task<List<Ticker>> GetTickers(Timeframe timeframe);
Task<Trade> OpenTakeProfit(Account account, Ticker ticker, TradeDirection originalDirection, Task<Trade> OpenTakeProfit(Account account, Ticker ticker, TradeDirection originalDirection,
decimal takeProfitPrice, decimal takeProfitPrice,

View File

@@ -178,14 +178,22 @@ namespace Managing.Application.ManageBot
{ {
if (_botTasks.TryRemove(botName, out var botWrapper)) if (_botTasks.TryRemove(botName, out var botWrapper))
{ {
if (botWrapper.BotInstance is IBot bot) try
{ {
await Task.Run(() => if (botWrapper.BotInstance is IBot bot)
bot.Stop()); // Assuming Stop is an asynchronous process wrapped in Task.Run for synchronous methods {
} await Task.Run(() =>
bot.Stop()); // Assuming Stop is an asynchronous process wrapped in Task.Run for synchronous methods
}
_botRepository.DeleteBotBackup(botName); await _botRepository.DeleteBotBackup(botName);
return true; return true;
}
catch (Exception e)
{
Console.WriteLine(e);
return false;
}
} }
return false; return false;

View File

@@ -34,8 +34,9 @@ public class BotRepository : IBotRepository
_botRepository.Update(dto); _botRepository.Update(dto);
} }
public void DeleteBotBackup(string botName) public async Task DeleteBotBackup(string botName)
{ {
_botRepository.DeleteOne(b => b.Name == botName); var backup = await _botRepository.FindOneAsync(b => b.Name == botName);
await _botRepository.DeleteOneAsync(b => b.Id == backup.Id);
} }
} }

View File

@@ -246,10 +246,10 @@ namespace Managing.Infrastructure.Exchanges
return processor.GetVolume(account, ticker); return processor.GetVolume(account, ticker);
} }
public async Task<List<Ticker>> GetTickers(Account account, Timeframe timeframe) public async Task<List<Ticker>> GetTickers(Timeframe timeframe)
{ {
var tickers = var tickers =
await _candleRepository.GetTickersAsync(account.Exchange, timeframe, DateTime.UtcNow.AddDays(-2)); await _candleRepository.GetTickersAsync(TradingExchanges.Evm, timeframe, DateTime.UtcNow.AddDays(-2));
return tickers.ToList(); return tickers.ToList();
} }

View File

@@ -157,7 +157,7 @@ const BacktestModal: React.FC<BacktestModalProps> = ({
enabled: !!selectedAccount && !!selectedTimeframe, enabled: !!selectedAccount && !!selectedTimeframe,
queryFn: () => { queryFn: () => {
if (selectedAccount && selectedTimeframe) { if (selectedAccount && selectedTimeframe) {
return dataClient.data_GetTickers(selectedAccount, selectedTimeframe) return dataClient.data_GetTickers(selectedTimeframe)
} }
}, },
queryKey: ['tickers', selectedAccount, selectedTimeframe], queryKey: ['tickers', selectedAccount, selectedTimeframe],

View File

@@ -116,12 +116,12 @@ const BacktestTable: React.FC<IBacktestCards> = ({ list, isFetching }) => {
accessor: 'botType', accessor: 'botType',
disableSortBy: true, disableSortBy: true,
}, },
{ // {
Filter: SelectColumnFilter, // Filter: SelectColumnFilter,
Header: 'Account', // Header: 'Account',
accessor: 'accountName', // accessor: 'accountName',
disableSortBy: true, // disableSortBy: true,
}, // },
], ],
}, },
{ {

View File

@@ -1,6 +1,6 @@
//---------------------- //----------------------
// <auto-generated> // <auto-generated>
// Generated using the NSwag toolchain v13.16.0.0 (NJsonSchema v10.7.1.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) // Generated using the NSwag toolchain v14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org)
// </auto-generated> // </auto-generated>
//---------------------- //----------------------
@@ -19,7 +19,7 @@ export class AccountClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) { constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration); super(configuration);
this.http = http ? http : window as any; this.http = http ? http : window as any;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "https://localhost:5001"; this.baseUrl = baseUrl ?? "http://localhost:5000";
} }
account_PostAccount(account: Account): Promise<Account> { account_PostAccount(account: Account): Promise<Account> {
@@ -123,8 +123,14 @@ export class AccountClient extends AuthorizedApiBase {
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200 || status === 206) { if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined;
if (fileName) {
fileName = decodeURIComponent(fileName);
} else {
fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
}
return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; }); return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; });
} else if (status !== 200 && status !== 204) { } else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => { return response.text().then((_responseText) => {
@@ -213,7 +219,7 @@ export class BacktestClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) { constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration); super(configuration);
this.http = http ? http : window as any; this.http = http ? http : window as any;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "https://localhost:5001"; this.baseUrl = baseUrl ?? "http://localhost:5000";
} }
backtest_Backtests(): Promise<Backtest[]> { backtest_Backtests(): Promise<Backtest[]> {
@@ -276,8 +282,14 @@ export class BacktestClient extends AuthorizedApiBase {
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200 || status === 206) { if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined;
if (fileName) {
fileName = decodeURIComponent(fileName);
} else {
fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
}
return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; }); return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; });
} else if (status !== 200 && status !== 204) { } else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => { return response.text().then((_responseText) => {
@@ -310,8 +322,14 @@ export class BacktestClient extends AuthorizedApiBase {
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200 || status === 206) { if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined;
if (fileName) {
fileName = decodeURIComponent(fileName);
} else {
fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
}
return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; }); return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; });
} else if (status !== 200 && status !== 204) { } else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => { return response.text().then((_responseText) => {
@@ -403,7 +421,7 @@ export class BotClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) { constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration); super(configuration);
this.http = http ? http : window as any; this.http = http ? http : window as any;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "https://localhost:5001"; this.baseUrl = baseUrl ?? "http://localhost:5000";
} }
bot_Start(request: StartBotRequest): Promise<string> { bot_Start(request: StartBotRequest): Promise<string> {
@@ -715,13 +733,11 @@ export class DataClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) { constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration); super(configuration);
this.http = http ? http : window as any; this.http = http ? http : window as any;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "https://localhost:5001"; this.baseUrl = baseUrl ?? "http://localhost:5000";
} }
data_GetTickers(accountName: string | null | undefined, timeframe: Timeframe | undefined): Promise<Ticker[]> { data_GetTickers(timeframe: Timeframe | undefined): Promise<Ticker[]> {
let url_ = this.baseUrl + "/Data/GetTickers?"; let url_ = this.baseUrl + "/Data/GetTickers?";
if (accountName !== undefined && accountName !== null)
url_ += "accountName=" + encodeURIComponent("" + accountName) + "&";
if (timeframe === null) if (timeframe === null)
throw new Error("The parameter 'timeframe' cannot be null."); throw new Error("The parameter 'timeframe' cannot be null.");
else if (timeframe !== undefined) else if (timeframe !== undefined)
@@ -854,7 +870,7 @@ export class MoneyManagementClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) { constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration); super(configuration);
this.http = http ? http : window as any; this.http = http ? http : window as any;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "https://localhost:5001"; this.baseUrl = baseUrl ?? "http://localhost:5000";
} }
moneyManagement_PostMoneyManagement(moneyManagement: MoneyManagement): Promise<MoneyManagement> { moneyManagement_PostMoneyManagement(moneyManagement: MoneyManagement): Promise<MoneyManagement> {
@@ -958,8 +974,14 @@ export class MoneyManagementClient extends AuthorizedApiBase {
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200 || status === 206) { if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined;
if (fileName) {
fileName = decodeURIComponent(fileName);
} else {
fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
}
return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; }); return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; });
} else if (status !== 200 && status !== 204) { } else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => { return response.text().then((_responseText) => {
@@ -1013,7 +1035,7 @@ export class ScenarioClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) { constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration); super(configuration);
this.http = http ? http : window as any; this.http = http ? http : window as any;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "https://localhost:5001"; this.baseUrl = baseUrl ?? "http://localhost:5000";
} }
scenario_GetScenarios(): Promise<Scenario[]> { scenario_GetScenarios(): Promise<Scenario[]> {
@@ -1117,8 +1139,14 @@ export class ScenarioClient extends AuthorizedApiBase {
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200 || status === 206) { if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined;
if (fileName) {
fileName = decodeURIComponent(fileName);
} else {
fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
}
return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; }); return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; });
} else if (status !== 200 && status !== 204) { } else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => { return response.text().then((_responseText) => {
@@ -1249,8 +1277,14 @@ export class ScenarioClient extends AuthorizedApiBase {
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200 || status === 206) { if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined;
if (fileName) {
fileName = decodeURIComponent(fileName);
} else {
fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
}
return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; }); return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; });
} else if (status !== 200 && status !== 204) { } else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => { return response.text().then((_responseText) => {
@@ -1269,7 +1303,7 @@ export class SettingsClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) { constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration); super(configuration);
this.http = http ? http : window as any; this.http = http ? http : window as any;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "https://localhost:5001"; this.baseUrl = baseUrl ?? "http://localhost:5000";
} }
settings_SetupSettings(): Promise<FileResponse> { settings_SetupSettings(): Promise<FileResponse> {
@@ -1295,8 +1329,14 @@ export class SettingsClient extends AuthorizedApiBase {
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200 || status === 206) { if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined;
if (fileName) {
fileName = decodeURIComponent(fileName);
} else {
fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
}
return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; }); return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; });
} else if (status !== 200 && status !== 204) { } else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => { return response.text().then((_responseText) => {
@@ -1350,7 +1390,7 @@ export class TradingClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) { constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration); super(configuration);
this.http = http ? http : window as any; this.http = http ? http : window as any;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "https://localhost:5001"; this.baseUrl = baseUrl ?? "http://localhost:5000";
} }
trading_GetPositions(positionInitiator: PositionInitiator | undefined): Promise<Position[]> { trading_GetPositions(positionInitiator: PositionInitiator | undefined): Promise<Position[]> {
@@ -1435,7 +1475,7 @@ export class TradingClient extends AuthorizedApiBase {
return Promise.resolve<Trade>(null as any); return Promise.resolve<Trade>(null as any);
} }
trading_GetTrades(accountName: string | null | undefined, ticker: Ticker | undefined, exchangeOrderId: string | null | undefined): Promise<Trade> { trading_GetTrades(accountName: string | null | undefined, ticker: Ticker | undefined): Promise<Trade> {
let url_ = this.baseUrl + "/Trading/GetTrades?"; let url_ = this.baseUrl + "/Trading/GetTrades?";
if (accountName !== undefined && accountName !== null) if (accountName !== undefined && accountName !== null)
url_ += "accountName=" + encodeURIComponent("" + accountName) + "&"; url_ += "accountName=" + encodeURIComponent("" + accountName) + "&";
@@ -1443,8 +1483,6 @@ export class TradingClient extends AuthorizedApiBase {
throw new Error("The parameter 'ticker' cannot be null."); throw new Error("The parameter 'ticker' cannot be null.");
else if (ticker !== undefined) else if (ticker !== undefined)
url_ += "ticker=" + encodeURIComponent("" + ticker) + "&"; url_ += "ticker=" + encodeURIComponent("" + ticker) + "&";
if (exchangeOrderId !== undefined && exchangeOrderId !== null)
url_ += "exchangeOrderId=" + encodeURIComponent("" + exchangeOrderId) + "&";
url_ = url_.replace(/[?&]$/, ""); url_ = url_.replace(/[?&]$/, "");
let options_: RequestInit = { let options_: RequestInit = {
@@ -1585,7 +1623,7 @@ export class UserClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) { constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration); super(configuration);
this.http = http ? http : window as any; this.http = http ? http : window as any;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "https://localhost:5001"; this.baseUrl = baseUrl ?? "http://localhost:5000";
} }
user_CreateToken(login: LoginRequest): Promise<string> { user_CreateToken(login: LoginRequest): Promise<string> {
@@ -1636,7 +1674,7 @@ export class WorkflowClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) { constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration); super(configuration);
this.http = http ? http : window as any; this.http = http ? http : window as any;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "https://localhost:5001"; this.baseUrl = baseUrl ?? "http://localhost:5000";
} }
workflow_PostWorkflow(workflowRequest: SyntheticWorkflow): Promise<Workflow> { workflow_PostWorkflow(workflowRequest: SyntheticWorkflow): Promise<Workflow> {
@@ -1738,8 +1776,14 @@ export class WorkflowClient extends AuthorizedApiBase {
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200 || status === 206) { if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined;
if (fileName) {
fileName = decodeURIComponent(fileName);
} else {
fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
}
return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; }); return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; });
} else if (status !== 200 && status !== 204) { } else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => { return response.text().then((_responseText) => {
@@ -1789,10 +1833,10 @@ export interface Account {
name: string; name: string;
exchange: TradingExchanges; exchange: TradingExchanges;
type: AccountType; type: AccountType;
key?: string | undefined; key?: string | null;
secret?: string | undefined; secret?: string | null;
user?: User | undefined; user?: User | null;
balances?: Balance[] | undefined; balances?: Balance[] | null;
} }
export enum TradingExchanges { export enum TradingExchanges {
@@ -1800,6 +1844,7 @@ export enum TradingExchanges {
Kraken = "Kraken", Kraken = "Kraken",
Ftx = "Ftx", Ftx = "Ftx",
Evm = "Evm", Evm = "Evm",
GmxV2 = "GmxV2",
} }
export enum AccountType { export enum AccountType {
@@ -1810,24 +1855,25 @@ export enum AccountType {
} }
export interface User { export interface User {
name?: string | undefined; name?: string | null;
accounts?: Account[] | undefined; accounts?: Account[] | null;
} }
export interface Balance { export interface Balance {
tokenImage?: string | undefined; tokenImage?: string | null;
tokenName?: string | undefined; tokenName?: string | null;
amount?: number; amount?: number;
price?: number; price?: number;
value?: number; value?: number;
tokenAdress?: string | undefined; tokenAdress?: string | null;
chain?: Chain | undefined; chain?: Chain | null;
} }
export interface Chain { export interface Chain {
id?: string | undefined; id?: string | null;
rpcUrl?: string | undefined; rpcUrl?: string | null;
name?: string | undefined; name?: string | null;
chainId?: number;
} }
export interface Backtest { export interface Backtest {
@@ -1852,25 +1898,20 @@ export interface Backtest {
} }
export enum Ticker { export enum Ticker {
AAVE = "AAVE",
ADA = "ADA", ADA = "ADA",
APE = "APE", APE = "APE",
ALICE = "ALICE",
ALGO = "ALGO", ALGO = "ALGO",
ARB = "ARB",
ATOM = "ATOM", ATOM = "ATOM",
AVAX = "AVAX", AVAX = "AVAX",
AXS = "AXS",
BAT = "BAT",
BNB = "BNB", BNB = "BNB",
BTC = "BTC", BTC = "BTC",
BAL = "BAL", BAL = "BAL",
C98 = "C98",
CHR = "CHR",
CHZ = "CHZ", CHZ = "CHZ",
COMP = "COMP", COMP = "COMP",
CRO = "CRO", CRO = "CRO",
CRV = "CRV", CRV = "CRV",
CVC = "CVC",
DEFI = "DEFI",
DOGE = "DOGE", DOGE = "DOGE",
DOT = "DOT", DOT = "DOT",
DYDX = "DYDX", DYDX = "DYDX",
@@ -1881,29 +1922,22 @@ export enum Ticker {
FLM = "FLM", FLM = "FLM",
FTM = "FTM", FTM = "FTM",
GALA = "GALA", GALA = "GALA",
GMT = "GMT",
GMX = "GMX", GMX = "GMX",
GRT = "GRT", GRT = "GRT",
HNT = "HNT",
IMX = "IMX", IMX = "IMX",
JASMY = "JASMY", JASMY = "JASMY",
KAVA = "KAVA",
KSM = "KSM", KSM = "KSM",
LDO = "LDO", LDO = "LDO",
LINK = "LINK", LINK = "LINK",
LOOKS = "LOOKS",
LRC = "LRC", LRC = "LRC",
LTC = "LTC", LTC = "LTC",
MANA = "MANA", MANA = "MANA",
MATIC = "MATIC", MATIC = "MATIC",
MKR = "MKR", MKR = "MKR",
NEAR = "NEAR", NEAR = "NEAR",
NEO = "NEO", OP = "OP",
OMG = "OMG", PEPE = "PEPE",
ONE = "ONE",
ONT = "ONT",
QTUM = "QTUM", QTUM = "QTUM",
REEF = "REEF",
REN = "REN", REN = "REN",
ROSE = "ROSE", ROSE = "ROSE",
RSR = "RSR", RSR = "RSR",
@@ -1911,21 +1945,19 @@ export enum Ticker {
SAND = "SAND", SAND = "SAND",
SOL = "SOL", SOL = "SOL",
SRM = "SRM", SRM = "SRM",
STMX = "STMX",
SUSHI = "SUSHI", SUSHI = "SUSHI",
SXP = "SXP",
THETA = "THETA", THETA = "THETA",
UNI = "UNI", UNI = "UNI",
USDC = "USDC", USDC = "USDC",
USDT = "USDT", USDT = "USDT",
VET = "VET", WIF = "WIF",
WAVES = "WAVES",
XMR = "XMR", XMR = "XMR",
XRP = "XRP", XRP = "XRP",
XTZ = "XTZ", XTZ = "XTZ",
YFI = "YFI", SHIB = "SHIB",
ZEC = "ZEC", STX = "STX",
ZIL = "ZIL", ORDI = "ORDI",
Unknown = "Unknown",
} }
export interface Position { export interface Position {
@@ -1937,10 +1969,10 @@ export interface Position {
open: Trade; open: Trade;
stopLoss: Trade; stopLoss: Trade;
takeProfit1: Trade; takeProfit1: Trade;
takeProfit2?: Trade | undefined; takeProfit2?: Trade | null;
profitAndLoss?: ProfitAndLoss | undefined; profitAndLoss?: ProfitAndLoss | null;
status: PositionStatus; status: PositionStatus;
signalIdentifier?: string | undefined; signalIdentifier?: string | null;
identifier: string; identifier: string;
initiator: PositionInitiator; initiator: PositionInitiator;
} }
@@ -1980,7 +2012,7 @@ export interface Trade {
price: number; price: number;
leverage?: number; leverage?: number;
exchangeOrderId: string; exchangeOrderId: string;
message?: string | undefined; message?: string | null;
} }
export enum TradeStatus { export enum TradeStatus {
@@ -2172,25 +2204,24 @@ export interface Spotlight {
} }
export interface Scenario { export interface Scenario {
name?: string | undefined; name?: string | null;
strategies?: Strategy[] | undefined; strategies?: Strategy[] | null;
} }
export interface Strategy { export interface Strategy {
name?: string | undefined; name?: string | null;
timeframe?: Timeframe; timeframe?: Timeframe;
candles?: Candle[] | undefined;
type?: StrategyType; type?: StrategyType;
signalType?: SignalType; signalType?: SignalType;
minimumHistory?: number; minimumHistory?: number;
period?: number | undefined; period?: number | null;
fastPeriods?: number | undefined; fastPeriods?: number | null;
slowPeriods?: number | undefined; slowPeriods?: number | null;
signalPeriods?: number | undefined; signalPeriods?: number | null;
multiplier?: number | undefined; multiplier?: number | null;
smoothPeriods?: number | undefined; smoothPeriods?: number | null;
stochPeriods?: number | undefined; stochPeriods?: number | null;
cyclePeriods?: number | undefined; cyclePeriods?: number | null;
} }
export interface TickerSignal { export interface TickerSignal {
@@ -2227,10 +2258,10 @@ export interface IFlow {
type: FlowType; type: FlowType;
description: string; description: string;
acceptedInputs: FlowOutput[]; acceptedInputs: FlowOutput[];
children?: IFlow[] | undefined; children?: IFlow[] | null;
parameters: FlowParameter[]; parameters: FlowParameter[];
parentId?: string; parentId?: string;
output?: string | undefined; output?: string | null;
outputTypes: FlowOutput[]; outputTypes: FlowOutput[];
} }
@@ -2248,8 +2279,8 @@ export enum FlowOutput {
} }
export interface FlowParameter { export interface FlowParameter {
value?: any | undefined; value?: any | null;
name?: string | undefined; name?: string | null;
} }
export interface SyntheticWorkflow { export interface SyntheticWorkflow {
@@ -2261,7 +2292,7 @@ export interface SyntheticWorkflow {
export interface SyntheticFlow { export interface SyntheticFlow {
id: string; id: string;
parentId?: string | undefined; parentId?: string | null;
type: FlowType; type: FlowType;
parameters: SyntheticFlowParameter[]; parameters: SyntheticFlowParameter[];
} }