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.Responses;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Application.Hubs;
using Managing.Application.ManageBot.Commands;
@@ -25,6 +26,7 @@ public class BotController : ControllerBase
private readonly ILogger<BotController> _logger;
private readonly IHubContext<BotHub> _hubContext;
private readonly IBacktester _backtester;
private readonly IBotService _botService;
/// <summary>
/// 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="backtester">Backtester for running backtests on bots.</param>
public BotController(ILogger<BotController> logger, IMediator mediator, IHubContext<BotHub> hubContext,
IBacktester backtester)
IBacktester backtester, IBotService botService)
{
_logger = logger;
_mediator = mediator;
_hubContext = hubContext;
_backtester = backtester;
_botService = botService;
}
/// <summary>
@@ -86,11 +89,8 @@ public class BotController : ControllerBase
[Route("Delete")]
public async Task<ActionResult<bool>> Delete(string botName)
{
var result = await _mediator.Send(new DeleteBotCommand(botName));
_logger.LogInformation($"{botName} is now deleted");
var result = await _botService.DeleteBot(botName);
await NotifyBotSubscriberAsync();
return Ok(result);
}

View File

@@ -51,16 +51,19 @@ public class DataController : ControllerBase
/// <summary>
/// Retrieves tickers for a given account and timeframe, utilizing caching to improve performance.
/// </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>
/// <returns>An array of tickers.</returns>
[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(accountName, timeframe.ToString());
var tickers = _cacheService.GetOrSave(cacheKey,
() => { return _exchangeService.GetTickers(account, timeframe).Result; }, TimeSpan.FromHours(2));
var cacheKey = string.Concat(timeframe.ToString());
var tickers = _cacheService.GetValue<List<Ticker>>(cacheKey);
if (tickers == null)
{
tickers = await _exchangeService.GetTickers(timeframe);
_cacheService.SaveValue(cacheKey, tickers, TimeSpan.FromHours(2));
}
return Ok(tickers);
}

View File

@@ -7,5 +7,5 @@ public interface IBotRepository
Task InsertBotAsync(BotBackup bot);
IEnumerable<BotBackup> GetBots();
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,
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,
decimal takeProfitPrice,

View File

@@ -177,6 +177,8 @@ namespace Managing.Application.ManageBot
public async Task<bool> DeleteBot(string botName)
{
if (_botTasks.TryRemove(botName, out var botWrapper))
{
try
{
if (botWrapper.BotInstance is IBot bot)
{
@@ -184,9 +186,15 @@ namespace Managing.Application.ManageBot
bot.Stop()); // Assuming Stop is an asynchronous process wrapped in Task.Run for synchronous methods
}
_botRepository.DeleteBotBackup(botName);
await _botRepository.DeleteBotBackup(botName);
return true;
}
catch (Exception e)
{
Console.WriteLine(e);
return false;
}
}
return false;
}

View File

@@ -34,8 +34,9 @@ public class BotRepository : IBotRepository
_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);
}
public async Task<List<Ticker>> GetTickers(Account account, Timeframe timeframe)
public async Task<List<Ticker>> GetTickers(Timeframe timeframe)
{
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();
}

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
//----------------------
// <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>
//----------------------
@@ -19,7 +19,7 @@ export class AccountClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration);
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> {
@@ -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); };
if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : 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 }; });
} else if (status !== 200 && status !== 204) {
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> }) {
super(configuration);
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[]> {
@@ -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); };
if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : 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 }; });
} else if (status !== 200 && status !== 204) {
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); };
if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : 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 }; });
} else if (status !== 200 && status !== 204) {
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> }) {
super(configuration);
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> {
@@ -715,13 +733,11 @@ export class DataClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration);
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?";
if (accountName !== undefined && accountName !== null)
url_ += "accountName=" + encodeURIComponent("" + accountName) + "&";
if (timeframe === null)
throw new Error("The parameter 'timeframe' cannot be null.");
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> }) {
super(configuration);
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> {
@@ -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); };
if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : 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 }; });
} else if (status !== 200 && status !== 204) {
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> }) {
super(configuration);
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[]> {
@@ -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); };
if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : 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 }; });
} else if (status !== 200 && status !== 204) {
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); };
if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : 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 }; });
} else if (status !== 200 && status !== 204) {
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> }) {
super(configuration);
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> {
@@ -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); };
if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : 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 }; });
} else if (status !== 200 && status !== 204) {
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> }) {
super(configuration);
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[]> {
@@ -1435,7 +1475,7 @@ export class TradingClient extends AuthorizedApiBase {
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?";
if (accountName !== undefined && accountName !== null)
url_ += "accountName=" + encodeURIComponent("" + accountName) + "&";
@@ -1443,8 +1483,6 @@ export class TradingClient extends AuthorizedApiBase {
throw new Error("The parameter 'ticker' cannot be null.");
else if (ticker !== undefined)
url_ += "ticker=" + encodeURIComponent("" + ticker) + "&";
if (exchangeOrderId !== undefined && exchangeOrderId !== null)
url_ += "exchangeOrderId=" + encodeURIComponent("" + exchangeOrderId) + "&";
url_ = url_.replace(/[?&]$/, "");
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> }) {
super(configuration);
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> {
@@ -1636,7 +1674,7 @@ export class WorkflowClient extends AuthorizedApiBase {
constructor(configuration: IConfig, baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
super(configuration);
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> {
@@ -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); };
if (status === 200 || status === 206) {
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : 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 }; });
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
@@ -1789,10 +1833,10 @@ export interface Account {
name: string;
exchange: TradingExchanges;
type: AccountType;
key?: string | undefined;
secret?: string | undefined;
user?: User | undefined;
balances?: Balance[] | undefined;
key?: string | null;
secret?: string | null;
user?: User | null;
balances?: Balance[] | null;
}
export enum TradingExchanges {
@@ -1800,6 +1844,7 @@ export enum TradingExchanges {
Kraken = "Kraken",
Ftx = "Ftx",
Evm = "Evm",
GmxV2 = "GmxV2",
}
export enum AccountType {
@@ -1810,24 +1855,25 @@ export enum AccountType {
}
export interface User {
name?: string | undefined;
accounts?: Account[] | undefined;
name?: string | null;
accounts?: Account[] | null;
}
export interface Balance {
tokenImage?: string | undefined;
tokenName?: string | undefined;
tokenImage?: string | null;
tokenName?: string | null;
amount?: number;
price?: number;
value?: number;
tokenAdress?: string | undefined;
chain?: Chain | undefined;
tokenAdress?: string | null;
chain?: Chain | null;
}
export interface Chain {
id?: string | undefined;
rpcUrl?: string | undefined;
name?: string | undefined;
id?: string | null;
rpcUrl?: string | null;
name?: string | null;
chainId?: number;
}
export interface Backtest {
@@ -1852,25 +1898,20 @@ export interface Backtest {
}
export enum Ticker {
AAVE = "AAVE",
ADA = "ADA",
APE = "APE",
ALICE = "ALICE",
ALGO = "ALGO",
ARB = "ARB",
ATOM = "ATOM",
AVAX = "AVAX",
AXS = "AXS",
BAT = "BAT",
BNB = "BNB",
BTC = "BTC",
BAL = "BAL",
C98 = "C98",
CHR = "CHR",
CHZ = "CHZ",
COMP = "COMP",
CRO = "CRO",
CRV = "CRV",
CVC = "CVC",
DEFI = "DEFI",
DOGE = "DOGE",
DOT = "DOT",
DYDX = "DYDX",
@@ -1881,29 +1922,22 @@ export enum Ticker {
FLM = "FLM",
FTM = "FTM",
GALA = "GALA",
GMT = "GMT",
GMX = "GMX",
GRT = "GRT",
HNT = "HNT",
IMX = "IMX",
JASMY = "JASMY",
KAVA = "KAVA",
KSM = "KSM",
LDO = "LDO",
LINK = "LINK",
LOOKS = "LOOKS",
LRC = "LRC",
LTC = "LTC",
MANA = "MANA",
MATIC = "MATIC",
MKR = "MKR",
NEAR = "NEAR",
NEO = "NEO",
OMG = "OMG",
ONE = "ONE",
ONT = "ONT",
OP = "OP",
PEPE = "PEPE",
QTUM = "QTUM",
REEF = "REEF",
REN = "REN",
ROSE = "ROSE",
RSR = "RSR",
@@ -1911,21 +1945,19 @@ export enum Ticker {
SAND = "SAND",
SOL = "SOL",
SRM = "SRM",
STMX = "STMX",
SUSHI = "SUSHI",
SXP = "SXP",
THETA = "THETA",
UNI = "UNI",
USDC = "USDC",
USDT = "USDT",
VET = "VET",
WAVES = "WAVES",
WIF = "WIF",
XMR = "XMR",
XRP = "XRP",
XTZ = "XTZ",
YFI = "YFI",
ZEC = "ZEC",
ZIL = "ZIL",
SHIB = "SHIB",
STX = "STX",
ORDI = "ORDI",
Unknown = "Unknown",
}
export interface Position {
@@ -1937,10 +1969,10 @@ export interface Position {
open: Trade;
stopLoss: Trade;
takeProfit1: Trade;
takeProfit2?: Trade | undefined;
profitAndLoss?: ProfitAndLoss | undefined;
takeProfit2?: Trade | null;
profitAndLoss?: ProfitAndLoss | null;
status: PositionStatus;
signalIdentifier?: string | undefined;
signalIdentifier?: string | null;
identifier: string;
initiator: PositionInitiator;
}
@@ -1980,7 +2012,7 @@ export interface Trade {
price: number;
leverage?: number;
exchangeOrderId: string;
message?: string | undefined;
message?: string | null;
}
export enum TradeStatus {
@@ -2172,25 +2204,24 @@ export interface Spotlight {
}
export interface Scenario {
name?: string | undefined;
strategies?: Strategy[] | undefined;
name?: string | null;
strategies?: Strategy[] | null;
}
export interface Strategy {
name?: string | undefined;
name?: string | null;
timeframe?: Timeframe;
candles?: Candle[] | undefined;
type?: StrategyType;
signalType?: SignalType;
minimumHistory?: number;
period?: number | undefined;
fastPeriods?: number | undefined;
slowPeriods?: number | undefined;
signalPeriods?: number | undefined;
multiplier?: number | undefined;
smoothPeriods?: number | undefined;
stochPeriods?: number | undefined;
cyclePeriods?: number | undefined;
period?: number | null;
fastPeriods?: number | null;
slowPeriods?: number | null;
signalPeriods?: number | null;
multiplier?: number | null;
smoothPeriods?: number | null;
stochPeriods?: number | null;
cyclePeriods?: number | null;
}
export interface TickerSignal {
@@ -2227,10 +2258,10 @@ export interface IFlow {
type: FlowType;
description: string;
acceptedInputs: FlowOutput[];
children?: IFlow[] | undefined;
children?: IFlow[] | null;
parameters: FlowParameter[];
parentId?: string;
output?: string | undefined;
output?: string | null;
outputTypes: FlowOutput[];
}
@@ -2248,8 +2279,8 @@ export enum FlowOutput {
}
export interface FlowParameter {
value?: any | undefined;
name?: string | undefined;
value?: any | null;
name?: string | null;
}
export interface SyntheticWorkflow {
@@ -2261,7 +2292,7 @@ export interface SyntheticWorkflow {
export interface SyntheticFlow {
id: string;
parentId?: string | undefined;
parentId?: string | null;
type: FlowType;
parameters: SyntheticFlowParameter[];
}