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