Update indicators
This commit is contained in:
@@ -171,7 +171,8 @@ public class BacktestController : BaseController
|
|||||||
FlipPosition = request.Config.FlipPosition,
|
FlipPosition = request.Config.FlipPosition,
|
||||||
Name = request.Config.Name ??
|
Name = request.Config.Name ??
|
||||||
$"Backtest-{request.Config.ScenarioName}-{DateTime.UtcNow:yyyyMMdd-HHmmss}",
|
$"Backtest-{request.Config.ScenarioName}-{DateTime.UtcNow:yyyyMMdd-HHmmss}",
|
||||||
CloseEarlyWhenProfitable = request.Config.CloseEarlyWhenProfitable
|
CloseEarlyWhenProfitable = request.Config.CloseEarlyWhenProfitable,
|
||||||
|
Scenario = scenario,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (request.Config.BotType)
|
switch (request.Config.BotType)
|
||||||
|
|||||||
@@ -1084,8 +1084,8 @@ namespace Managing.Application.Tests
|
|||||||
var scenarioName = string.Join("_",
|
var scenarioName = string.Join("_",
|
||||||
paramCombo.Select(p => $"{p.strategyConfig.Name}_{p.parameterSet.Name}"));
|
paramCombo.Select(p => $"{p.strategyConfig.Name}_{p.parameterSet.Name}"));
|
||||||
var scenario = BuildScenario(scenarioName, paramCombo);
|
var scenario = BuildScenario(scenarioName, paramCombo);
|
||||||
scenarios.Add(scenario);
|
|
||||||
scenario.LoopbackPeriod = 15;
|
scenario.LoopbackPeriod = 15;
|
||||||
|
scenarios.Add(scenario);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import React, {useEffect} from 'react'
|
import React, {useEffect} from 'react'
|
||||||
import {SubmitHandler, useForm} from 'react-hook-form'
|
import {SubmitHandler, useForm} from 'react-hook-form'
|
||||||
import {Modal} from '../../mollecules'
|
import {Modal} from '../../mollecules'
|
||||||
import type {Scenario, Strategy} from '../../../generated/ManagingApi'
|
import type {Indicator, Scenario} from '../../../generated/ManagingApi'
|
||||||
import type {IScenarioFormInput} from '../../../global/type'
|
import type {IScenarioFormInput} from '../../../global/type'
|
||||||
|
|
||||||
interface ScenarioModalProps {
|
interface ScenarioModalProps {
|
||||||
showModal: boolean
|
showModal: boolean
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
onSubmit: (data: IScenarioFormInput) => Promise<void>
|
onSubmit: (data: IScenarioFormInput) => Promise<void>
|
||||||
strategies: Strategy[]
|
indicators: Indicator[]
|
||||||
scenario?: Scenario | null // For update mode
|
scenario?: Scenario | null // For update mode
|
||||||
isUpdate?: boolean
|
isUpdate?: boolean
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ const ScenarioModal: React.FC<ScenarioModalProps> = ({
|
|||||||
showModal,
|
showModal,
|
||||||
onClose,
|
onClose,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
strategies,
|
indicators,
|
||||||
scenario = null,
|
scenario = null,
|
||||||
isUpdate = false
|
isUpdate = false
|
||||||
}) => {
|
}) => {
|
||||||
@@ -30,7 +30,7 @@ const ScenarioModal: React.FC<ScenarioModalProps> = ({
|
|||||||
// Pre-populate form for update
|
// Pre-populate form for update
|
||||||
setValue('name', scenario.name || '')
|
setValue('name', scenario.name || '')
|
||||||
setValue('loopbackPeriod', scenario.loopbackPeriod || 0)
|
setValue('loopbackPeriod', scenario.loopbackPeriod || 0)
|
||||||
setValue('strategies', scenario.strategies?.map(s => s.name || '') || [])
|
setValue('indicators', scenario.indicators?.map(s => s.name || '') || [])
|
||||||
} else {
|
} else {
|
||||||
// Reset form for create
|
// Reset form for create
|
||||||
reset()
|
reset()
|
||||||
@@ -68,15 +68,15 @@ const ScenarioModal: React.FC<ScenarioModalProps> = ({
|
|||||||
|
|
||||||
<div className="form-control">
|
<div className="form-control">
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
<label htmlFor="strategies" className="label mr-6">
|
<label htmlFor="indicators" className="label mr-6">
|
||||||
Strategies
|
Indicators
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
multiple
|
multiple
|
||||||
className="select select-bordered h-28 w-full max-w-xs"
|
className="select select-bordered h-28 w-full max-w-xs"
|
||||||
{...register('strategies')}
|
{...register('indicators')}
|
||||||
>
|
>
|
||||||
{strategies.map((item) => (
|
{indicators?.map((item) => (
|
||||||
<option key={item.name} value={item.name || ''}>
|
<option key={item.name} value={item.name || ''}>
|
||||||
{item.signalType} - {item.name}
|
{item.signalType} - {item.name}
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
@@ -1600,8 +1600,8 @@ export class ScenarioClient extends AuthorizedApiBase {
|
|||||||
return Promise.resolve<FileResponse>(null as any);
|
return Promise.resolve<FileResponse>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
scenario_GetStrategies(): Promise<Strategy[]> {
|
scenario_GetIndicators(): Promise<Indicator[]> {
|
||||||
let url_ = this.baseUrl + "/Scenario/strategy";
|
let url_ = this.baseUrl + "/Scenario/indicator";
|
||||||
url_ = url_.replace(/[?&]$/, "");
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
let options_: RequestInit = {
|
let options_: RequestInit = {
|
||||||
@@ -1614,17 +1614,17 @@ export class ScenarioClient extends AuthorizedApiBase {
|
|||||||
return this.transformOptions(options_).then(transformedOptions_ => {
|
return this.transformOptions(options_).then(transformedOptions_ => {
|
||||||
return this.http.fetch(url_, transformedOptions_);
|
return this.http.fetch(url_, transformedOptions_);
|
||||||
}).then((_response: Response) => {
|
}).then((_response: Response) => {
|
||||||
return this.processScenario_GetStrategies(_response);
|
return this.processScenario_GetIndicators(_response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected processScenario_GetStrategies(response: Response): Promise<Strategy[]> {
|
protected processScenario_GetIndicators(response: Response): Promise<Indicator[]> {
|
||||||
const status = response.status;
|
const status = response.status;
|
||||||
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) {
|
if (status === 200) {
|
||||||
return response.text().then((_responseText) => {
|
return response.text().then((_responseText) => {
|
||||||
let result200: any = null;
|
let result200: any = null;
|
||||||
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as Strategy[];
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as Indicator[];
|
||||||
return result200;
|
return result200;
|
||||||
});
|
});
|
||||||
} else if (status !== 200 && status !== 204) {
|
} else if (status !== 200 && status !== 204) {
|
||||||
@@ -1632,15 +1632,15 @@ export class ScenarioClient extends AuthorizedApiBase {
|
|||||||
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.resolve<Strategy[]>(null as any);
|
return Promise.resolve<Indicator[]>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
scenario_CreateStrategy(strategyType: StrategyType | undefined, name: string | null | undefined, period: number | null | undefined, fastPeriods: number | null | undefined, slowPeriods: number | null | undefined, signalPeriods: number | null | undefined, multiplier: number | null | undefined, stochPeriods: number | null | undefined, smoothPeriods: number | null | undefined, cyclePeriods: number | null | undefined): Promise<Strategy> {
|
scenario_CreateIndicator(indicatorType: IndicatorType | undefined, name: string | null | undefined, period: number | null | undefined, fastPeriods: number | null | undefined, slowPeriods: number | null | undefined, signalPeriods: number | null | undefined, multiplier: number | null | undefined, stochPeriods: number | null | undefined, smoothPeriods: number | null | undefined, cyclePeriods: number | null | undefined): Promise<Indicator> {
|
||||||
let url_ = this.baseUrl + "/Scenario/strategy?";
|
let url_ = this.baseUrl + "/Scenario/indicator?";
|
||||||
if (strategyType === null)
|
if (indicatorType === null)
|
||||||
throw new Error("The parameter 'strategyType' cannot be null.");
|
throw new Error("The parameter 'indicatorType' cannot be null.");
|
||||||
else if (strategyType !== undefined)
|
else if (indicatorType !== undefined)
|
||||||
url_ += "strategyType=" + encodeURIComponent("" + strategyType) + "&";
|
url_ += "indicatorType=" + encodeURIComponent("" + indicatorType) + "&";
|
||||||
if (name !== undefined && name !== null)
|
if (name !== undefined && name !== null)
|
||||||
url_ += "name=" + encodeURIComponent("" + name) + "&";
|
url_ += "name=" + encodeURIComponent("" + name) + "&";
|
||||||
if (period !== undefined && period !== null)
|
if (period !== undefined && period !== null)
|
||||||
@@ -1671,17 +1671,17 @@ export class ScenarioClient extends AuthorizedApiBase {
|
|||||||
return this.transformOptions(options_).then(transformedOptions_ => {
|
return this.transformOptions(options_).then(transformedOptions_ => {
|
||||||
return this.http.fetch(url_, transformedOptions_);
|
return this.http.fetch(url_, transformedOptions_);
|
||||||
}).then((_response: Response) => {
|
}).then((_response: Response) => {
|
||||||
return this.processScenario_CreateStrategy(_response);
|
return this.processScenario_CreateIndicator(_response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected processScenario_CreateStrategy(response: Response): Promise<Strategy> {
|
protected processScenario_CreateIndicator(response: Response): Promise<Indicator> {
|
||||||
const status = response.status;
|
const status = response.status;
|
||||||
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) {
|
if (status === 200) {
|
||||||
return response.text().then((_responseText) => {
|
return response.text().then((_responseText) => {
|
||||||
let result200: any = null;
|
let result200: any = null;
|
||||||
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as Strategy;
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as Indicator;
|
||||||
return result200;
|
return result200;
|
||||||
});
|
});
|
||||||
} else if (status !== 200 && status !== 204) {
|
} else if (status !== 200 && status !== 204) {
|
||||||
@@ -1689,11 +1689,11 @@ export class ScenarioClient extends AuthorizedApiBase {
|
|||||||
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.resolve<Strategy>(null as any);
|
return Promise.resolve<Indicator>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
scenario_DeleteStrategy(name: string | null | undefined): Promise<FileResponse> {
|
scenario_DeleteIndicator(name: string | null | undefined): Promise<FileResponse> {
|
||||||
let url_ = this.baseUrl + "/Scenario/strategy?";
|
let url_ = this.baseUrl + "/Scenario/indicator?";
|
||||||
if (name !== undefined && name !== null)
|
if (name !== undefined && name !== null)
|
||||||
url_ += "name=" + encodeURIComponent("" + name) + "&";
|
url_ += "name=" + encodeURIComponent("" + name) + "&";
|
||||||
url_ = url_.replace(/[?&]$/, "");
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
@@ -1708,11 +1708,11 @@ export class ScenarioClient extends AuthorizedApiBase {
|
|||||||
return this.transformOptions(options_).then(transformedOptions_ => {
|
return this.transformOptions(options_).then(transformedOptions_ => {
|
||||||
return this.http.fetch(url_, transformedOptions_);
|
return this.http.fetch(url_, transformedOptions_);
|
||||||
}).then((_response: Response) => {
|
}).then((_response: Response) => {
|
||||||
return this.processScenario_DeleteStrategy(_response);
|
return this.processScenario_DeleteIndicator(_response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected processScenario_DeleteStrategy(response: Response): Promise<FileResponse> {
|
protected processScenario_DeleteIndicator(response: Response): Promise<FileResponse> {
|
||||||
const status = response.status;
|
const status = response.status;
|
||||||
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) {
|
||||||
@@ -1734,12 +1734,12 @@ export class ScenarioClient extends AuthorizedApiBase {
|
|||||||
return Promise.resolve<FileResponse>(null as any);
|
return Promise.resolve<FileResponse>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
scenario_UpdateStrategy(strategyType: StrategyType | undefined, name: string | null | undefined, period: number | null | undefined, fastPeriods: number | null | undefined, slowPeriods: number | null | undefined, signalPeriods: number | null | undefined, multiplier: number | null | undefined, stochPeriods: number | null | undefined, smoothPeriods: number | null | undefined, cyclePeriods: number | null | undefined): Promise<FileResponse> {
|
scenario_Updateindicator(indicatorType: IndicatorType | undefined, name: string | null | undefined, period: number | null | undefined, fastPeriods: number | null | undefined, slowPeriods: number | null | undefined, signalPeriods: number | null | undefined, multiplier: number | null | undefined, stochPeriods: number | null | undefined, smoothPeriods: number | null | undefined, cyclePeriods: number | null | undefined): Promise<FileResponse> {
|
||||||
let url_ = this.baseUrl + "/Scenario/strategy?";
|
let url_ = this.baseUrl + "/Scenario/indicator?";
|
||||||
if (strategyType === null)
|
if (indicatorType === null)
|
||||||
throw new Error("The parameter 'strategyType' cannot be null.");
|
throw new Error("The parameter 'indicatorType' cannot be null.");
|
||||||
else if (strategyType !== undefined)
|
else if (indicatorType !== undefined)
|
||||||
url_ += "strategyType=" + encodeURIComponent("" + strategyType) + "&";
|
url_ += "indicatorType=" + encodeURIComponent("" + indicatorType) + "&";
|
||||||
if (name !== undefined && name !== null)
|
if (name !== undefined && name !== null)
|
||||||
url_ += "name=" + encodeURIComponent("" + name) + "&";
|
url_ += "name=" + encodeURIComponent("" + name) + "&";
|
||||||
if (period !== undefined && period !== null)
|
if (period !== undefined && period !== null)
|
||||||
@@ -1770,11 +1770,11 @@ export class ScenarioClient extends AuthorizedApiBase {
|
|||||||
return this.transformOptions(options_).then(transformedOptions_ => {
|
return this.transformOptions(options_).then(transformedOptions_ => {
|
||||||
return this.http.fetch(url_, transformedOptions_);
|
return this.http.fetch(url_, transformedOptions_);
|
||||||
}).then((_response: Response) => {
|
}).then((_response: Response) => {
|
||||||
return this.processScenario_UpdateStrategy(_response);
|
return this.processScenario_Updateindicator(_response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected processScenario_UpdateStrategy(response: Response): Promise<FileResponse> {
|
protected processScenario_Updateindicator(response: Response): Promise<FileResponse> {
|
||||||
const status = response.status;
|
const status = response.status;
|
||||||
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) {
|
||||||
@@ -2745,46 +2745,23 @@ export interface GmxClaimableSummary {
|
|||||||
claimableFundingFees?: FundingFeesData | null;
|
claimableFundingFees?: FundingFeesData | null;
|
||||||
claimableUiFees?: UiFeesData | null;
|
claimableUiFees?: UiFeesData | null;
|
||||||
rebateStats?: RebateStatsData | null;
|
rebateStats?: RebateStatsData | null;
|
||||||
summary?: SummaryData | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FundingFeesData {
|
export interface FundingFeesData {
|
||||||
totalLongUsdc?: number;
|
|
||||||
totalShortUsdc?: number;
|
|
||||||
totalUsdc?: number;
|
totalUsdc?: number;
|
||||||
markets?: { [key: string]: FundingFeesMarketData; } | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FundingFeesMarketData {
|
|
||||||
claimableFundingAmountLong?: number;
|
|
||||||
claimableFundingAmountShort?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UiFeesData {
|
export interface UiFeesData {
|
||||||
totalUsdc?: number;
|
totalUsdc?: number;
|
||||||
markets?: { [key: string]: UiFeesMarketData; } | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UiFeesMarketData {
|
|
||||||
claimableUiFeeAmount?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RebateStatsData {
|
export interface RebateStatsData {
|
||||||
totalRebateUsdc?: number;
|
totalRebateUsdc?: number;
|
||||||
discountUsdc?: number;
|
discountUsdc?: number;
|
||||||
volume?: number;
|
|
||||||
tier?: number;
|
|
||||||
rebateFactor?: number;
|
rebateFactor?: number;
|
||||||
discountFactor?: number;
|
discountFactor?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SummaryData {
|
|
||||||
totalClaimableUsdc?: number;
|
|
||||||
hasFundingFees?: boolean;
|
|
||||||
hasUiFees?: boolean;
|
|
||||||
hasRebates?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Backtest {
|
export interface Backtest {
|
||||||
id: string;
|
id: string;
|
||||||
finalPnl: number;
|
finalPnl: number;
|
||||||
@@ -2802,7 +2779,7 @@ export interface Backtest {
|
|||||||
walletBalances: KeyValuePairOfDateTimeAndDecimal[];
|
walletBalances: KeyValuePairOfDateTimeAndDecimal[];
|
||||||
optimizedMoneyManagement: MoneyManagement;
|
optimizedMoneyManagement: MoneyManagement;
|
||||||
user: User;
|
user: User;
|
||||||
strategiesValues: { [key in keyof typeof StrategyType]?: StrategiesResultBase; };
|
strategiesValues: { [key in keyof typeof IndicatorType]?: IndicatorsResultBase; };
|
||||||
score: number;
|
score: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2810,7 +2787,6 @@ export interface TradingBotConfig {
|
|||||||
accountName: string;
|
accountName: string;
|
||||||
moneyManagement: MoneyManagement;
|
moneyManagement: MoneyManagement;
|
||||||
ticker: Ticker;
|
ticker: Ticker;
|
||||||
scenarioName: string;
|
|
||||||
timeframe: Timeframe;
|
timeframe: Timeframe;
|
||||||
isForWatchingOnly: boolean;
|
isForWatchingOnly: boolean;
|
||||||
botTradingBalance: number;
|
botTradingBalance: number;
|
||||||
@@ -2820,6 +2796,8 @@ export interface TradingBotConfig {
|
|||||||
maxLossStreak: number;
|
maxLossStreak: number;
|
||||||
flipPosition: boolean;
|
flipPosition: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
|
scenario?: Scenario | null;
|
||||||
|
scenarioName?: string | null;
|
||||||
maxPositionTimeHours?: number | null;
|
maxPositionTimeHours?: number | null;
|
||||||
closeEarlyWhenProfitable?: boolean;
|
closeEarlyWhenProfitable?: boolean;
|
||||||
flipOnlyWhenInProfit: boolean;
|
flipOnlyWhenInProfit: boolean;
|
||||||
@@ -2959,6 +2937,53 @@ export enum BotType {
|
|||||||
FlippingBot = "FlippingBot",
|
FlippingBot = "FlippingBot",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Scenario {
|
||||||
|
name?: string | null;
|
||||||
|
indicators?: Indicator[] | null;
|
||||||
|
loopbackPeriod?: number | null;
|
||||||
|
user?: User | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Indicator {
|
||||||
|
name?: string | null;
|
||||||
|
type?: IndicatorType;
|
||||||
|
signalType?: SignalType;
|
||||||
|
minimumHistory?: number;
|
||||||
|
period?: number | null;
|
||||||
|
fastPeriods?: number | null;
|
||||||
|
slowPeriods?: number | null;
|
||||||
|
signalPeriods?: number | null;
|
||||||
|
multiplier?: number | null;
|
||||||
|
smoothPeriods?: number | null;
|
||||||
|
stochPeriods?: number | null;
|
||||||
|
cyclePeriods?: number | null;
|
||||||
|
user?: User | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum IndicatorType {
|
||||||
|
RsiDivergence = "RsiDivergence",
|
||||||
|
RsiDivergenceConfirm = "RsiDivergenceConfirm",
|
||||||
|
MacdCross = "MacdCross",
|
||||||
|
EmaCross = "EmaCross",
|
||||||
|
ThreeWhiteSoldiers = "ThreeWhiteSoldiers",
|
||||||
|
SuperTrend = "SuperTrend",
|
||||||
|
ChandelierExit = "ChandelierExit",
|
||||||
|
EmaTrend = "EmaTrend",
|
||||||
|
Composite = "Composite",
|
||||||
|
StochRsiTrend = "StochRsiTrend",
|
||||||
|
Stc = "Stc",
|
||||||
|
StDev = "StDev",
|
||||||
|
LaggingStc = "LaggingStc",
|
||||||
|
SuperTrendCrossEma = "SuperTrendCrossEma",
|
||||||
|
DualEmaCross = "DualEmaCross",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum SignalType {
|
||||||
|
Signal = "Signal",
|
||||||
|
Trend = "Trend",
|
||||||
|
Context = "Context",
|
||||||
|
}
|
||||||
|
|
||||||
export interface Position {
|
export interface Position {
|
||||||
accountName: string;
|
accountName: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
@@ -3058,7 +3083,7 @@ export interface Signal extends ValueObject {
|
|||||||
identifier: string;
|
identifier: string;
|
||||||
ticker: Ticker;
|
ticker: Ticker;
|
||||||
exchange: TradingExchanges;
|
exchange: TradingExchanges;
|
||||||
strategyType: StrategyType;
|
indicatorType: IndicatorType;
|
||||||
signalType: SignalType;
|
signalType: SignalType;
|
||||||
user?: User | null;
|
user?: User | null;
|
||||||
}
|
}
|
||||||
@@ -3094,30 +3119,6 @@ export interface Candle {
|
|||||||
timeframe: Timeframe;
|
timeframe: Timeframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum StrategyType {
|
|
||||||
RsiDivergence = "RsiDivergence",
|
|
||||||
RsiDivergenceConfirm = "RsiDivergenceConfirm",
|
|
||||||
MacdCross = "MacdCross",
|
|
||||||
EmaCross = "EmaCross",
|
|
||||||
ThreeWhiteSoldiers = "ThreeWhiteSoldiers",
|
|
||||||
SuperTrend = "SuperTrend",
|
|
||||||
ChandelierExit = "ChandelierExit",
|
|
||||||
EmaTrend = "EmaTrend",
|
|
||||||
Composite = "Composite",
|
|
||||||
StochRsiTrend = "StochRsiTrend",
|
|
||||||
Stc = "Stc",
|
|
||||||
StDev = "StDev",
|
|
||||||
LaggingStc = "LaggingStc",
|
|
||||||
SuperTrendCrossEma = "SuperTrendCrossEma",
|
|
||||||
DualEmaCross = "DualEmaCross",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum SignalType {
|
|
||||||
Signal = "Signal",
|
|
||||||
Trend = "Trend",
|
|
||||||
Context = "Context",
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PerformanceMetrics {
|
export interface PerformanceMetrics {
|
||||||
count?: number;
|
count?: number;
|
||||||
sharpeRatio?: number;
|
sharpeRatio?: number;
|
||||||
@@ -3134,7 +3135,7 @@ export interface KeyValuePairOfDateTimeAndDecimal {
|
|||||||
value?: number;
|
value?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StrategiesResultBase {
|
export interface IndicatorsResultBase {
|
||||||
ema?: EmaResult[] | null;
|
ema?: EmaResult[] | null;
|
||||||
fastEma?: EmaResult[] | null;
|
fastEma?: EmaResult[] | null;
|
||||||
slowEma?: EmaResult[] | null;
|
slowEma?: EmaResult[] | null;
|
||||||
@@ -3285,29 +3286,6 @@ export interface Spotlight {
|
|||||||
tickerSignals: TickerSignal[];
|
tickerSignals: TickerSignal[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Scenario {
|
|
||||||
name?: string | null;
|
|
||||||
strategies?: Strategy[] | null;
|
|
||||||
loopbackPeriod?: number | null;
|
|
||||||
user?: User | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Strategy {
|
|
||||||
name?: string | null;
|
|
||||||
type?: StrategyType;
|
|
||||||
signalType?: SignalType;
|
|
||||||
minimumHistory?: number;
|
|
||||||
period?: number | null;
|
|
||||||
fastPeriods?: number | null;
|
|
||||||
slowPeriods?: number | null;
|
|
||||||
signalPeriods?: number | null;
|
|
||||||
multiplier?: number | null;
|
|
||||||
smoothPeriods?: number | null;
|
|
||||||
stochPeriods?: number | null;
|
|
||||||
cyclePeriods?: number | null;
|
|
||||||
user?: User | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TickerSignal {
|
export interface TickerSignal {
|
||||||
ticker: Ticker;
|
ticker: Ticker;
|
||||||
fiveMinutes: Signal[];
|
fiveMinutes: Signal[];
|
||||||
|
|||||||
@@ -7,20 +7,15 @@ import type {
|
|||||||
Backtest,
|
Backtest,
|
||||||
Balance,
|
Balance,
|
||||||
BotType,
|
BotType,
|
||||||
Candle,
|
|
||||||
FlowOutput,
|
FlowOutput,
|
||||||
FlowType,
|
FlowType,
|
||||||
IFlow,
|
IFlow,
|
||||||
KeyValuePairOfDateTimeAndDecimal,
|
Indicator,
|
||||||
MoneyManagement,
|
MoneyManagement,
|
||||||
PerformanceMetrics,
|
|
||||||
Position,
|
Position,
|
||||||
RiskLevel,
|
RiskLevel,
|
||||||
Scenario,
|
Scenario,
|
||||||
Signal,
|
Signal,
|
||||||
StrategiesResultBase,
|
|
||||||
Strategy,
|
|
||||||
StrategyType,
|
|
||||||
Ticker,
|
Ticker,
|
||||||
Timeframe,
|
Timeframe,
|
||||||
TradeDirection,
|
TradeDirection,
|
||||||
@@ -150,16 +145,6 @@ export type IMoneyManagementModalProps = {
|
|||||||
moneyManagement?: MoneyManagement
|
moneyManagement?: MoneyManagement
|
||||||
disableInputs?: boolean
|
disableInputs?: boolean
|
||||||
}
|
}
|
||||||
export type IBotRowDetails = {
|
|
||||||
candles: Candle[]
|
|
||||||
positions: Position[]
|
|
||||||
walletBalances?: KeyValuePairOfDateTimeAndDecimal[] | null
|
|
||||||
strategiesValues?: { [key in keyof typeof StrategyType]?: StrategiesResultBase; } | null;
|
|
||||||
signals: Signal[]
|
|
||||||
optimizedMoneyManagement: MoneyManagement
|
|
||||||
statistics: PerformanceMetrics
|
|
||||||
moneyManagement: MoneyManagement
|
|
||||||
}
|
|
||||||
|
|
||||||
export type IBacktestFormInput = {
|
export type IBacktestFormInput = {
|
||||||
accountName: string
|
accountName: string
|
||||||
@@ -188,12 +173,12 @@ export type IBotList = {
|
|||||||
}
|
}
|
||||||
export type IScenarioFormInput = {
|
export type IScenarioFormInput = {
|
||||||
name: string
|
name: string
|
||||||
strategies: string[]
|
indicators: string[]
|
||||||
loopbackPeriod: number | undefined
|
loopbackPeriod: number | undefined
|
||||||
}
|
}
|
||||||
export type IScenarioList = {
|
export type IScenarioList = {
|
||||||
list: Scenario[]
|
list: Scenario[]
|
||||||
strategies?: Strategy[]
|
indicators?: Indicator[]
|
||||||
setScenarios?: React.Dispatch<React.SetStateAction<Scenario[]>>
|
setScenarios?: React.Dispatch<React.SetStateAction<Scenario[]>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
433
src/Managing.WebApp/src/pages/scenarioPage/indicatorList.tsx
Normal file
433
src/Managing.WebApp/src/pages/scenarioPage/indicatorList.tsx
Normal file
@@ -0,0 +1,433 @@
|
|||||||
|
import React, {useEffect, useState} from 'react'
|
||||||
|
import type {SubmitHandler} from 'react-hook-form'
|
||||||
|
import {useForm} from 'react-hook-form'
|
||||||
|
import 'react-toastify/dist/ReactToastify.css'
|
||||||
|
|
||||||
|
import useApiUrlStore from '../../app/store/apiStore'
|
||||||
|
import {Toast} from '../../components/mollecules'
|
||||||
|
import type {Indicator} from '../../generated/ManagingApi'
|
||||||
|
import {IndicatorType, ScenarioClient, Timeframe,} from '../../generated/ManagingApi'
|
||||||
|
|
||||||
|
import IndicatorTable from './indicatorTable'
|
||||||
|
|
||||||
|
interface IIndicatorFormInput {
|
||||||
|
type: IndicatorType
|
||||||
|
timeframe: Timeframe
|
||||||
|
name: string
|
||||||
|
period: number
|
||||||
|
fastPeriods: number
|
||||||
|
slowPeriods: number
|
||||||
|
signalPeriods: number
|
||||||
|
multiplier: number
|
||||||
|
stochPeriods: number
|
||||||
|
smoothPeriods: number
|
||||||
|
cyclePeriods: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const IndicatorList: React.FC = () => {
|
||||||
|
const [indicatorType, setIndicatorType] = useState<IndicatorType>(
|
||||||
|
IndicatorType.RsiDivergence
|
||||||
|
)
|
||||||
|
const [indicators, setIndicators] = useState<Indicator[]>([])
|
||||||
|
const [showModal, setShowModal] = useState(false)
|
||||||
|
const { register, handleSubmit } = useForm<IIndicatorFormInput>()
|
||||||
|
const { apiUrl } = useApiUrlStore()
|
||||||
|
const scenarioClient = new ScenarioClient({}, apiUrl)
|
||||||
|
|
||||||
|
async function createIndicator(form: IIndicatorFormInput) {
|
||||||
|
const t = new Toast('Creating indicator')
|
||||||
|
await scenarioClient
|
||||||
|
.scenario_CreateIndicator(
|
||||||
|
form.type,
|
||||||
|
form.name,
|
||||||
|
form.period,
|
||||||
|
form.fastPeriods,
|
||||||
|
form.slowPeriods,
|
||||||
|
form.signalPeriods,
|
||||||
|
form.multiplier,
|
||||||
|
form.stochPeriods,
|
||||||
|
form.smoothPeriods,
|
||||||
|
form.cyclePeriods
|
||||||
|
)
|
||||||
|
.then((indicator: Indicator) => {
|
||||||
|
t.update('success', 'Indicator created')
|
||||||
|
setIndicators((arr) => [...arr, indicator])
|
||||||
|
})
|
||||||
|
.catch((err: any) => {
|
||||||
|
t.update('error', err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function setIndicatorTypeEvent(e: any) {
|
||||||
|
setIndicatorType(e.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<IIndicatorFormInput> = async (form) => {
|
||||||
|
closeModal()
|
||||||
|
await createIndicator(form)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
scenarioClient.scenario_GetIndicators().then((data: Indicator[]) => {
|
||||||
|
setIndicators(data)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
function openModal() {
|
||||||
|
setShowModal(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeModal() {
|
||||||
|
setShowModal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="container mx-auto">
|
||||||
|
<button className="btn" onClick={openModal}>
|
||||||
|
Create indicator
|
||||||
|
</button>
|
||||||
|
<IndicatorTable list={indicators} />
|
||||||
|
{showModal ? (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<div className="modal modal-bottom sm:modal-middle modal-open">
|
||||||
|
<div className="modal-box">
|
||||||
|
<button
|
||||||
|
onClick={closeModal}
|
||||||
|
className="btn btn-sm btn-circle right-2 top-2 absolute"
|
||||||
|
>
|
||||||
|
✕
|
||||||
|
</button>
|
||||||
|
<div className="text-primary mb-3 text-lg">
|
||||||
|
Indicator builder
|
||||||
|
</div>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="name" className="label mr-6">
|
||||||
|
Name
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
className="bg-inherit w-full max-w-xs"
|
||||||
|
{...register('name')}
|
||||||
|
></input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="type" className="label mr-6">
|
||||||
|
Type
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
className="select w-full max-w-xs"
|
||||||
|
{...register('type', {
|
||||||
|
onChange: (e) => {
|
||||||
|
setIndicatorTypeEvent(e)
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{Object.keys(IndicatorType).map((item) => (
|
||||||
|
<option key={item} value={item}>
|
||||||
|
{item}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="timeframe" className="label mr-6">
|
||||||
|
Timeframe
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
className="select w-full max-w-xs"
|
||||||
|
{...register('timeframe')}
|
||||||
|
>
|
||||||
|
{Object.keys(Timeframe).map((item) => (
|
||||||
|
<option key={item} value={item}>
|
||||||
|
{item}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{indicatorType == IndicatorType.EmaTrend ||
|
||||||
|
indicatorType == IndicatorType.RsiDivergence ||
|
||||||
|
indicatorType == IndicatorType.StDev ||
|
||||||
|
indicatorType == IndicatorType.EmaCross ||
|
||||||
|
indicatorType == IndicatorType.RsiDivergenceConfirm ? (
|
||||||
|
<>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Period
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="5"
|
||||||
|
className="input"
|
||||||
|
{...register('period')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{indicatorType == IndicatorType.MacdCross ? (
|
||||||
|
<>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Fast Periods
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="12"
|
||||||
|
className="input"
|
||||||
|
{...register('fastPeriods')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Slow Periods
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="26"
|
||||||
|
className="input"
|
||||||
|
{...register('slowPeriods')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Signal Periods
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="9"
|
||||||
|
className="input"
|
||||||
|
{...register('signalPeriods')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{indicatorType == IndicatorType.DualEmaCross ? (
|
||||||
|
<>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Fast Periods
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="9"
|
||||||
|
className="input"
|
||||||
|
{...register('fastPeriods')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Slow Periods
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="21"
|
||||||
|
className="input"
|
||||||
|
{...register('slowPeriods')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{indicatorType == IndicatorType.Stc || indicatorType == IndicatorType.LaggingStc ? (
|
||||||
|
<>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Fast Periods
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="23"
|
||||||
|
className="input"
|
||||||
|
{...register('fastPeriods')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Slow Periods
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="50"
|
||||||
|
className="input"
|
||||||
|
{...register('slowPeriods')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Cycle Periods
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="10"
|
||||||
|
className="input"
|
||||||
|
{...register('cyclePeriods')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{indicatorType == IndicatorType.SuperTrend ||
|
||||||
|
indicatorType == IndicatorType.SuperTrendCrossEma ||
|
||||||
|
indicatorType == IndicatorType.ChandelierExit ? (
|
||||||
|
<>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Period
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="10"
|
||||||
|
className="input"
|
||||||
|
{...register('period')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="multiplier" className="label mr-6">
|
||||||
|
Multiplier
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="3"
|
||||||
|
className="input"
|
||||||
|
step="any"
|
||||||
|
{...register('multiplier')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{indicatorType == IndicatorType.StochRsiTrend ? (
|
||||||
|
<>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Periods
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="14"
|
||||||
|
className="input"
|
||||||
|
{...register('period')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Stoch Periods
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="14"
|
||||||
|
className="input"
|
||||||
|
{...register('stochPeriods')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Signal Periods
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="3"
|
||||||
|
className="input"
|
||||||
|
{...register('signalPeriods')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-control">
|
||||||
|
<div className="input-group">
|
||||||
|
<label htmlFor="period" className="label mr-6">
|
||||||
|
Smooth Periods
|
||||||
|
</label>
|
||||||
|
<label className="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="1"
|
||||||
|
className="input"
|
||||||
|
{...register('smoothPeriods')}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
<div className="modal-action">
|
||||||
|
<button type="submit" className="btn">
|
||||||
|
Build
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IndicatorList
|
||||||
@@ -3,25 +3,25 @@ import React, { useEffect, useState } from 'react'
|
|||||||
|
|
||||||
import useApiUrlStore from '../../app/store/apiStore'
|
import useApiUrlStore from '../../app/store/apiStore'
|
||||||
import {SelectColumnFilter, Table, Toast} from '../../components/mollecules'
|
import {SelectColumnFilter, Table, Toast} from '../../components/mollecules'
|
||||||
import type { Strategy } from '../../generated/ManagingApi'
|
import type {Indicator} from '../../generated/ManagingApi'
|
||||||
import {ScenarioClient} from '../../generated/ManagingApi'
|
import {ScenarioClient} from '../../generated/ManagingApi'
|
||||||
|
|
||||||
interface IStrategyList {
|
interface IIndicatorList {
|
||||||
list: Strategy[]
|
list: Indicator[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const StrategyTable: React.FC<IStrategyList> = ({ list }) => {
|
const IndicatorTable: React.FC<IIndicatorList> = ({ list }) => {
|
||||||
const [rows, setRows] = useState<Strategy[]>([])
|
const [rows, setRows] = useState<Indicator[]>([])
|
||||||
const { apiUrl } = useApiUrlStore()
|
const { apiUrl } = useApiUrlStore()
|
||||||
|
|
||||||
async function deleteBacktest(id: string) {
|
async function deleteIndicator(name: string) {
|
||||||
const t = new Toast('Deleting strategy')
|
const t = new Toast('Deleting indicator')
|
||||||
const client = new ScenarioClient({}, apiUrl)
|
const client = new ScenarioClient({}, apiUrl)
|
||||||
|
|
||||||
await client
|
await client
|
||||||
.scenario_DeleteStrategy(id)
|
.scenario_DeleteIndicator(name)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
t.update('info', 'Strategy deleted')
|
t.update('info', 'Indicator deleted')
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
t.update('error', err)
|
t.update('error', err)
|
||||||
@@ -62,10 +62,10 @@ const StrategyTable: React.FC<IStrategyList> = ({ list }) => {
|
|||||||
{
|
{
|
||||||
Cell: ({ cell }: any) => (
|
Cell: ({ cell }: any) => (
|
||||||
<>
|
<>
|
||||||
<div className="tooltip" data-tip="Delete strategy">
|
<div className="tooltip" data-tip="Delete indicator">
|
||||||
<button
|
<button
|
||||||
data-value={cell.row.values.name}
|
data-value={cell.row.values.name}
|
||||||
onClick={() => deleteBacktest(cell.row.values.name)}
|
onClick={() => deleteIndicator(cell.row.values.name)}
|
||||||
>
|
>
|
||||||
<TrashIcon className="text-accent w-4"></TrashIcon>
|
<TrashIcon className="text-accent w-4"></TrashIcon>
|
||||||
</button>
|
</button>
|
||||||
@@ -91,4 +91,4 @@ const StrategyTable: React.FC<IStrategyList> = ({ list }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default StrategyTable
|
export default IndicatorTable
|
||||||
@@ -5,7 +5,7 @@ import { Tabs } from '../../components/mollecules'
|
|||||||
import type {TabsType} from '../../global/type'
|
import type {TabsType} from '../../global/type'
|
||||||
|
|
||||||
import ScenarioList from './scenarioList'
|
import ScenarioList from './scenarioList'
|
||||||
import StrategyList from './strategyList'
|
import IndicatorList from './indicatorList'
|
||||||
|
|
||||||
// Tabs Array
|
// Tabs Array
|
||||||
const tabs: TabsType = [
|
const tabs: TabsType = [
|
||||||
@@ -15,7 +15,7 @@ const tabs: TabsType = [
|
|||||||
label: 'Scenarios',
|
label: 'Scenarios',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Component: StrategyList,
|
Component: IndicatorList,
|
||||||
index: 2,
|
index: 2,
|
||||||
label: 'Strategies',
|
label: 'Strategies',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import 'react-toastify/dist/ReactToastify.css'
|
|||||||
import useApiUrlStore from '../../app/store/apiStore'
|
import useApiUrlStore from '../../app/store/apiStore'
|
||||||
import {Toast} from '../../components/mollecules'
|
import {Toast} from '../../components/mollecules'
|
||||||
import {ScenarioModal} from '../../components/organism'
|
import {ScenarioModal} from '../../components/organism'
|
||||||
import type {Scenario, Strategy} from '../../generated/ManagingApi'
|
import type {Indicator, Scenario} from '../../generated/ManagingApi'
|
||||||
import {ScenarioClient} from '../../generated/ManagingApi'
|
import {ScenarioClient} from '../../generated/ManagingApi'
|
||||||
import type {IScenarioFormInput} from '../../global/type'
|
import type {IScenarioFormInput} from '../../global/type'
|
||||||
|
|
||||||
import ScenarioTable from './scenarioTable'
|
import ScenarioTable from './scenarioTable'
|
||||||
|
|
||||||
const ScenarioList: React.FC = () => {
|
const ScenarioList: React.FC = () => {
|
||||||
const [strategies, setStrategies] = useState<Strategy[]>([])
|
const [indicators, setIndicators] = useState<Indicator[]>([])
|
||||||
const [scenarios, setScenarios] = useState<Scenario[]>([])
|
const [scenarios, setScenarios] = useState<Scenario[]>([])
|
||||||
const [showModal, setShowModal] = useState(false)
|
const [showModal, setShowModal] = useState(false)
|
||||||
const { apiUrl } = useApiUrlStore()
|
const { apiUrl } = useApiUrlStore()
|
||||||
@@ -20,7 +20,7 @@ const ScenarioList: React.FC = () => {
|
|||||||
async function createScenario(form: IScenarioFormInput) {
|
async function createScenario(form: IScenarioFormInput) {
|
||||||
const t = new Toast('Creating scenario')
|
const t = new Toast('Creating scenario')
|
||||||
await client
|
await client
|
||||||
.scenario_CreateScenario(form.name, form.loopbackPeriod, form.strategies)
|
.scenario_CreateScenario(form.name, form.loopbackPeriod, form.indicators)
|
||||||
.then((data: Scenario) => {
|
.then((data: Scenario) => {
|
||||||
t.update('success', 'Scenario created')
|
t.update('success', 'Scenario created')
|
||||||
setScenarios((arr) => [...arr, data])
|
setScenarios((arr) => [...arr, data])
|
||||||
@@ -38,8 +38,8 @@ const ScenarioList: React.FC = () => {
|
|||||||
client.scenario_GetScenarios().then((data) => {
|
client.scenario_GetScenarios().then((data) => {
|
||||||
setScenarios(data)
|
setScenarios(data)
|
||||||
})
|
})
|
||||||
client.scenario_GetStrategies().then((data) => {
|
client.scenario_GetIndicators().then((data) => {
|
||||||
setStrategies(data)
|
setIndicators(data)
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@@ -56,12 +56,12 @@ const ScenarioList: React.FC = () => {
|
|||||||
<button className="btn" onClick={openModal}>
|
<button className="btn" onClick={openModal}>
|
||||||
Create new scenario
|
Create new scenario
|
||||||
</button>
|
</button>
|
||||||
<ScenarioTable list={scenarios} strategies={strategies} setScenarios={setScenarios} />
|
<ScenarioTable list={scenarios} indicators={indicators} setScenarios={setScenarios} />
|
||||||
<ScenarioModal
|
<ScenarioModal
|
||||||
showModal={showModal}
|
showModal={showModal}
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
strategies={strategies}
|
indicators={indicators}
|
||||||
isUpdate={false}
|
isUpdate={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import React, {useEffect, useState} from 'react'
|
|||||||
import useApiUrlStore from '../../app/store/apiStore'
|
import useApiUrlStore from '../../app/store/apiStore'
|
||||||
import {Table, Toast} from '../../components/mollecules'
|
import {Table, Toast} from '../../components/mollecules'
|
||||||
import {ScenarioModal} from '../../components/organism'
|
import {ScenarioModal} from '../../components/organism'
|
||||||
import type {Scenario, Strategy} from '../../generated/ManagingApi'
|
import type {Indicator, Scenario} from '../../generated/ManagingApi'
|
||||||
import {ScenarioClient} from '../../generated/ManagingApi'
|
import {ScenarioClient} from '../../generated/ManagingApi'
|
||||||
import type {IScenarioFormInput, IScenarioList} from '../../global/type'
|
import type {IScenarioFormInput, IScenarioList} from '../../global/type'
|
||||||
|
|
||||||
const ScenarioTable: React.FC<IScenarioList> = ({ list, strategies = [], setScenarios }) => {
|
const ScenarioTable: React.FC<IScenarioList> = ({ list, indicators = [], setScenarios }) => {
|
||||||
const [rows, setRows] = useState<Scenario[]>([])
|
const [rows, setRows] = useState<Scenario[]>([])
|
||||||
const [showUpdateModal, setShowUpdateModal] = useState(false)
|
const [showUpdateModal, setShowUpdateModal] = useState(false)
|
||||||
const [selectedScenario, setSelectedScenario] = useState<Scenario | null>(null)
|
const [selectedScenario, setSelectedScenario] = useState<Scenario | null>(null)
|
||||||
@@ -38,7 +38,7 @@ const ScenarioTable: React.FC<IScenarioList> = ({ list, strategies = [], setScen
|
|||||||
const t = new Toast('Updating scenario')
|
const t = new Toast('Updating scenario')
|
||||||
|
|
||||||
await client
|
await client
|
||||||
.scenario_UpdateScenario(form.name, form.loopbackPeriod, form.strategies)
|
.scenario_UpdateScenario(form.name, form.loopbackPeriod, form.indicators)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
t.update('success', 'Scenario updated')
|
t.update('success', 'Scenario updated')
|
||||||
// Refetch scenarios after update since the API returns FileResponse
|
// Refetch scenarios after update since the API returns FileResponse
|
||||||
@@ -77,18 +77,18 @@ const ScenarioTable: React.FC<IScenarioList> = ({ list, strategies = [], setScen
|
|||||||
{
|
{
|
||||||
Cell: ({ cell }: any) => (
|
Cell: ({ cell }: any) => (
|
||||||
<>
|
<>
|
||||||
{cell.row.values.strategies.map((strategy: Strategy) => (
|
{cell.row.values.indicators.map((indicator: Indicator) => (
|
||||||
<div
|
<div
|
||||||
key={strategy.name}
|
key={indicator.name}
|
||||||
className="badge badge-primary badge-outline"
|
className="badge badge-primary badge-outline"
|
||||||
>
|
>
|
||||||
{strategy.name}
|
{indicator.name}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
Header: 'Strategies',
|
Header: 'Indicators',
|
||||||
accessor: 'strategies',
|
accessor: 'indicators',
|
||||||
disableFilters: true,
|
disableFilters: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -135,7 +135,7 @@ const ScenarioTable: React.FC<IScenarioList> = ({ list, strategies = [], setScen
|
|||||||
showModal={showUpdateModal}
|
showModal={showUpdateModal}
|
||||||
onClose={closeUpdateModal}
|
onClose={closeUpdateModal}
|
||||||
onSubmit={handleUpdateSubmit}
|
onSubmit={handleUpdateSubmit}
|
||||||
strategies={strategies}
|
indicators={indicators}
|
||||||
scenario={selectedScenario}
|
scenario={selectedScenario}
|
||||||
isUpdate={true}
|
isUpdate={true}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import 'react-toastify/dist/ReactToastify.css'
|
|||||||
|
|
||||||
import useApiUrlStore from '../../app/store/apiStore'
|
import useApiUrlStore from '../../app/store/apiStore'
|
||||||
import {Toast} from '../../components/mollecules'
|
import {Toast} from '../../components/mollecules'
|
||||||
import type {Strategy} from '../../generated/ManagingApi'
|
import type {Indicator} from '../../generated/ManagingApi'
|
||||||
import {ScenarioClient, StrategyType, Timeframe,} from '../../generated/ManagingApi'
|
import {IndicatorType, ScenarioClient, Timeframe,} from '../../generated/ManagingApi'
|
||||||
|
|
||||||
import StrategyTable from './strategyTable'
|
import IndicatorTable from './indicatorTable'
|
||||||
|
|
||||||
interface IStrategyFormInput {
|
interface IIndicatorFormInput {
|
||||||
type: StrategyType
|
type: IndicatorType
|
||||||
timeframe: Timeframe
|
timeframe: Timeframe
|
||||||
name: string
|
name: string
|
||||||
period: number
|
period: number
|
||||||
@@ -24,20 +24,20 @@ interface IStrategyFormInput {
|
|||||||
cyclePeriods: number
|
cyclePeriods: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const StrategyList: React.FC = () => {
|
const IndicatorList: React.FC = () => {
|
||||||
const [strategyType, setStrategyType] = useState<StrategyType>(
|
const [indicatorType, setIndicatorType] = useState<IndicatorType>(
|
||||||
StrategyType.RsiDivergence
|
IndicatorType.RsiDivergence
|
||||||
)
|
)
|
||||||
const [strategies, setStrategies] = useState<Strategy[]>([])
|
const [indicators, setIndicators] = useState<Indicator[]>([])
|
||||||
const [showModal, setShowModal] = useState(false)
|
const [showModal, setShowModal] = useState(false)
|
||||||
const { register, handleSubmit } = useForm<IStrategyFormInput>()
|
const { register, handleSubmit } = useForm<IIndicatorFormInput>()
|
||||||
const { apiUrl } = useApiUrlStore()
|
const { apiUrl } = useApiUrlStore()
|
||||||
const scenarioClient = new ScenarioClient({}, apiUrl)
|
const scenarioClient = new ScenarioClient({}, apiUrl)
|
||||||
|
|
||||||
async function createStrategy(form: IStrategyFormInput) {
|
async function createIndicator(form: IIndicatorFormInput) {
|
||||||
const t = new Toast('Creating strategy')
|
const t = new Toast('Creating indicator')
|
||||||
await scenarioClient
|
await scenarioClient
|
||||||
.scenario_CreateStrategy(
|
.scenario_CreateIndicator(
|
||||||
form.type,
|
form.type,
|
||||||
form.name,
|
form.name,
|
||||||
form.period,
|
form.period,
|
||||||
@@ -49,27 +49,27 @@ const StrategyList: React.FC = () => {
|
|||||||
form.smoothPeriods,
|
form.smoothPeriods,
|
||||||
form.cyclePeriods
|
form.cyclePeriods
|
||||||
)
|
)
|
||||||
.then((strategy: Strategy) => {
|
.then((indicator: Indicator) => {
|
||||||
t.update('success', 'Strategy created')
|
t.update('success', 'Indicator created')
|
||||||
setStrategies((arr) => [...arr, strategy])
|
setIndicators((arr) => [...arr, indicator])
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err: any) => {
|
||||||
t.update('error', err)
|
t.update('error', err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function setStrategyTypeEvent(e: any) {
|
function setIndicatorTypeEvent(e: any) {
|
||||||
setStrategyType(e.target.value)
|
setIndicatorType(e.target.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSubmit: SubmitHandler<IStrategyFormInput> = async (form) => {
|
const onSubmit: SubmitHandler<IIndicatorFormInput> = async (form) => {
|
||||||
closeModal()
|
closeModal()
|
||||||
await createStrategy(form)
|
await createIndicator(form)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
scenarioClient.scenario_GetStrategies().then((data) => {
|
scenarioClient.scenario_GetIndicators().then((data: Indicator[]) => {
|
||||||
setStrategies(data)
|
setIndicators(data)
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@@ -85,9 +85,9 @@ const StrategyList: React.FC = () => {
|
|||||||
<div>
|
<div>
|
||||||
<div className="container mx-auto">
|
<div className="container mx-auto">
|
||||||
<button className="btn" onClick={openModal}>
|
<button className="btn" onClick={openModal}>
|
||||||
Create strategy
|
Create indicator
|
||||||
</button>
|
</button>
|
||||||
<StrategyTable list={strategies} />
|
<IndicatorTable list={indicators} />
|
||||||
{showModal ? (
|
{showModal ? (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
@@ -101,7 +101,7 @@ const StrategyList: React.FC = () => {
|
|||||||
✕
|
✕
|
||||||
</button>
|
</button>
|
||||||
<div className="text-primary mb-3 text-lg">
|
<div className="text-primary mb-3 text-lg">
|
||||||
Strategy builder
|
Indicator builder
|
||||||
</div>
|
</div>
|
||||||
<div className="form-control">
|
<div className="form-control">
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
@@ -123,11 +123,11 @@ const StrategyList: React.FC = () => {
|
|||||||
className="select w-full max-w-xs"
|
className="select w-full max-w-xs"
|
||||||
{...register('type', {
|
{...register('type', {
|
||||||
onChange: (e) => {
|
onChange: (e) => {
|
||||||
setStrategyTypeEvent(e)
|
setIndicatorTypeEvent(e)
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{Object.keys(StrategyType).map((item) => (
|
{Object.keys(IndicatorType).map((item) => (
|
||||||
<option key={item} value={item}>
|
<option key={item} value={item}>
|
||||||
{item}
|
{item}
|
||||||
</option>
|
</option>
|
||||||
@@ -153,11 +153,11 @@ const StrategyList: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{strategyType == StrategyType.EmaTrend ||
|
{indicatorType == IndicatorType.EmaTrend ||
|
||||||
strategyType == StrategyType.RsiDivergence ||
|
indicatorType == IndicatorType.RsiDivergence ||
|
||||||
strategyType == StrategyType.StDev ||
|
indicatorType == IndicatorType.StDev ||
|
||||||
strategyType == StrategyType.EmaCross ||
|
indicatorType == IndicatorType.EmaCross ||
|
||||||
strategyType == StrategyType.RsiDivergenceConfirm ? (
|
indicatorType == IndicatorType.RsiDivergenceConfirm ? (
|
||||||
<>
|
<>
|
||||||
<div className="form-control">
|
<div className="form-control">
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
@@ -177,7 +177,7 @@ const StrategyList: React.FC = () => {
|
|||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{strategyType == StrategyType.MacdCross ? (
|
{indicatorType == IndicatorType.MacdCross ? (
|
||||||
<>
|
<>
|
||||||
<div className="form-control">
|
<div className="form-control">
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
@@ -227,7 +227,7 @@ const StrategyList: React.FC = () => {
|
|||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{strategyType == StrategyType.DualEmaCross ? (
|
{indicatorType == IndicatorType.DualEmaCross ? (
|
||||||
<>
|
<>
|
||||||
<div className="form-control">
|
<div className="form-control">
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
@@ -262,7 +262,7 @@ const StrategyList: React.FC = () => {
|
|||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{strategyType == StrategyType.Stc || strategyType == StrategyType.LaggingStc ? (
|
{indicatorType == IndicatorType.Stc || indicatorType == IndicatorType.LaggingStc ? (
|
||||||
<>
|
<>
|
||||||
<div className="form-control">
|
<div className="form-control">
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
@@ -312,9 +312,9 @@ const StrategyList: React.FC = () => {
|
|||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{strategyType == StrategyType.SuperTrend ||
|
{indicatorType == IndicatorType.SuperTrend ||
|
||||||
strategyType == StrategyType.SuperTrendCrossEma ||
|
indicatorType == IndicatorType.SuperTrendCrossEma ||
|
||||||
strategyType == StrategyType.ChandelierExit ? (
|
indicatorType == IndicatorType.ChandelierExit ? (
|
||||||
<>
|
<>
|
||||||
<div className="form-control">
|
<div className="form-control">
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
@@ -349,7 +349,7 @@ const StrategyList: React.FC = () => {
|
|||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{strategyType == StrategyType.StochRsiTrend ? (
|
{indicatorType == IndicatorType.StochRsiTrend ? (
|
||||||
<>
|
<>
|
||||||
<div className="form-control">
|
<div className="form-control">
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
@@ -429,4 +429,4 @@ const StrategyList: React.FC = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default StrategyList
|
export default IndicatorList
|
||||||
|
|||||||
Reference in New Issue
Block a user