Add IchimokuKumoTrend indicator support across application
- Introduced IchimokuKumoTrend indicator in GeneticService with configuration settings for tenkanPeriods, kijunPeriods, senkouBPeriods, offsetPeriods, senkouOffset, and chikouOffset. - Updated ScenarioHelpers to handle creation and validation of the new indicator type. - Enhanced CustomScenario, backtest, and scenario pages to include IchimokuKumoTrend in indicator lists and parameter mappings. - Modified API and types to reflect the addition of the new indicator in relevant enums and mappings.
This commit is contained in:
@@ -63,7 +63,11 @@ const CustomScenario: React.FC<ICustomScenario> = ({
|
||||
case IndicatorType.LaggingStc:
|
||||
params = ['cyclePeriods', 'fastPeriods', 'slowPeriods'];
|
||||
break;
|
||||
|
||||
|
||||
case IndicatorType.IchimokuKumoTrend:
|
||||
params = ['tenkanPeriods', 'kijunPeriods', 'senkouBPeriods', 'offsetPeriods'];
|
||||
break;
|
||||
|
||||
case IndicatorType.Composite:
|
||||
params = []; // Composite might not need specific parameters
|
||||
break;
|
||||
@@ -123,6 +127,9 @@ const CustomScenario: React.FC<ICustomScenario> = ({
|
||||
case IndicatorType.Composite:
|
||||
label = 'Composite';
|
||||
break;
|
||||
case IndicatorType.IchimokuKumoTrend:
|
||||
label = 'Ichimoku Kumo Trend';
|
||||
break;
|
||||
default:
|
||||
label = type;
|
||||
break;
|
||||
@@ -142,7 +149,13 @@ const CustomScenario: React.FC<ICustomScenario> = ({
|
||||
multiplier: 3.0,
|
||||
stochPeriods: 14,
|
||||
smoothPeriods: 3,
|
||||
cyclePeriods: 10
|
||||
cyclePeriods: 10,
|
||||
tenkanPeriods: 9,
|
||||
kijunPeriods: 26,
|
||||
senkouBPeriods: 52,
|
||||
offsetPeriods: 26,
|
||||
senkouOffset: 26,
|
||||
chikouOffset: 26
|
||||
}
|
||||
setIndicators([...indicators, newIndicator])
|
||||
}
|
||||
|
||||
@@ -14,14 +14,15 @@ import moment from 'moment'
|
||||
import * as React from 'react'
|
||||
import {useEffect, useRef, useState} from 'react'
|
||||
|
||||
import type {
|
||||
import {
|
||||
Candle,
|
||||
IndicatorsResultBase,
|
||||
IndicatorType,
|
||||
LightSignal,
|
||||
Position,
|
||||
PositionStatus,
|
||||
TradeDirection,
|
||||
} from '../../../../generated/ManagingApi'
|
||||
import {PositionStatus, TradeDirection,} from '../../../../generated/ManagingApi'
|
||||
import useTheme from '../../../../hooks/useTheme'
|
||||
|
||||
// var customTheme = {
|
||||
@@ -485,6 +486,47 @@ const TradeChart = ({
|
||||
chandelierExitsShortsSeries.setData(chandelierExitsShorts)
|
||||
}
|
||||
|
||||
// Display Ichimoku Cloud (Kumo)
|
||||
if (indicatorsValues?.[IndicatorType.IchimokuKumoTrend]?.ichimoku != null) {
|
||||
const senkouSpanASeries = chart.current.addLineSeries({
|
||||
color: theme.secondary,
|
||||
lineWidth: 1,
|
||||
priceLineVisible: false,
|
||||
priceLineWidth: 1,
|
||||
title: 'Senkou Span A',
|
||||
pane: 0,
|
||||
lineStyle: LineStyle.Solid,
|
||||
})
|
||||
|
||||
const senkouSpanAData = indicatorsValues[IndicatorType.IchimokuKumoTrend].ichimoku?.map((w) => {
|
||||
return {
|
||||
time: moment(w.date).unix(),
|
||||
value: w.senkouSpanA,
|
||||
}
|
||||
})
|
||||
// @ts-ignore
|
||||
senkouSpanASeries.setData(senkouSpanAData)
|
||||
|
||||
const senkouSpanBSeries = chart.current.addLineSeries({
|
||||
color: theme.accent,
|
||||
lineWidth: 1,
|
||||
priceLineVisible: false,
|
||||
priceLineWidth: 1,
|
||||
title: 'Senkou Span B',
|
||||
pane: 0,
|
||||
lineStyle: LineStyle.Solid,
|
||||
})
|
||||
|
||||
const senkouSpanBData = indicatorsValues[IndicatorType.IchimokuKumoTrend].ichimoku?.map((w) => {
|
||||
return {
|
||||
time: moment(w.date).unix(),
|
||||
value: w.senkouSpanB,
|
||||
}
|
||||
})
|
||||
// @ts-ignore
|
||||
senkouSpanBSeries.setData(senkouSpanBData)
|
||||
}
|
||||
|
||||
// Display Bollinger Bands on price chart
|
||||
if (indicatorsValues?.BollingerBandsPercentBMomentumBreakout != null) {
|
||||
const upperBandSeries = chart.current.addLineSeries({
|
||||
|
||||
@@ -4965,6 +4965,12 @@ export interface LightIndicator {
|
||||
cyclePeriods?: number | null;
|
||||
kFactor?: number | null;
|
||||
dFactor?: number | null;
|
||||
tenkanPeriods?: number | null;
|
||||
kijunPeriods?: number | null;
|
||||
senkouBPeriods?: number | null;
|
||||
offsetPeriods?: number | null;
|
||||
senkouOffset?: number | null;
|
||||
chikouOffset?: number | null;
|
||||
}
|
||||
|
||||
export enum IndicatorType {
|
||||
@@ -4985,6 +4991,7 @@ export enum IndicatorType {
|
||||
SuperTrendCrossEma = "SuperTrendCrossEma",
|
||||
DualEmaCross = "DualEmaCross",
|
||||
BollingerBandsPercentBMomentumBreakout = "BollingerBandsPercentBMomentumBreakout",
|
||||
IchimokuKumoTrend = "IchimokuKumoTrend",
|
||||
}
|
||||
|
||||
export enum SignalType {
|
||||
@@ -5575,6 +5582,12 @@ export interface IndicatorBase {
|
||||
cyclePeriods?: number | null;
|
||||
kFactor?: number | null;
|
||||
dFactor?: number | null;
|
||||
tenkanPeriods?: number | null;
|
||||
kijunPeriods?: number | null;
|
||||
senkouBPeriods?: number | null;
|
||||
offsetPeriods?: number | null;
|
||||
senkouOffset?: number | null;
|
||||
chikouOffset?: number | null;
|
||||
user?: User | null;
|
||||
}
|
||||
|
||||
@@ -5606,6 +5619,7 @@ export interface IndicatorsResultBase {
|
||||
stdDev?: StdDevResult[] | null;
|
||||
superTrend?: SuperTrendResult[] | null;
|
||||
chandelierLong?: ChandelierResult[] | null;
|
||||
ichimoku?: IchimokuResult[] | null;
|
||||
}
|
||||
|
||||
export interface ResultBase {
|
||||
@@ -5682,6 +5696,14 @@ export interface SuperTrendResult extends ResultBase {
|
||||
lowerBand?: number | null;
|
||||
}
|
||||
|
||||
export interface IchimokuResult extends ResultBase {
|
||||
tenkanSen?: number | null;
|
||||
kijunSen?: number | null;
|
||||
senkouSpanA?: number | null;
|
||||
senkouSpanB?: number | null;
|
||||
chikouSpan?: number | null;
|
||||
}
|
||||
|
||||
export interface GetCandlesWithIndicatorsRequest {
|
||||
ticker?: Ticker;
|
||||
startDate?: Date;
|
||||
|
||||
@@ -431,6 +431,12 @@ export interface LightIndicator {
|
||||
cyclePeriods?: number | null;
|
||||
kFactor?: number | null;
|
||||
dFactor?: number | null;
|
||||
tenkanPeriods?: number | null;
|
||||
kijunPeriods?: number | null;
|
||||
senkouBPeriods?: number | null;
|
||||
offsetPeriods?: number | null;
|
||||
senkouOffset?: number | null;
|
||||
chikouOffset?: number | null;
|
||||
}
|
||||
|
||||
export enum IndicatorType {
|
||||
@@ -451,6 +457,7 @@ export enum IndicatorType {
|
||||
SuperTrendCrossEma = "SuperTrendCrossEma",
|
||||
DualEmaCross = "DualEmaCross",
|
||||
BollingerBandsPercentBMomentumBreakout = "BollingerBandsPercentBMomentumBreakout",
|
||||
IchimokuKumoTrend = "IchimokuKumoTrend",
|
||||
}
|
||||
|
||||
export enum SignalType {
|
||||
@@ -1041,6 +1048,12 @@ export interface IndicatorBase {
|
||||
cyclePeriods?: number | null;
|
||||
kFactor?: number | null;
|
||||
dFactor?: number | null;
|
||||
tenkanPeriods?: number | null;
|
||||
kijunPeriods?: number | null;
|
||||
senkouBPeriods?: number | null;
|
||||
offsetPeriods?: number | null;
|
||||
senkouOffset?: number | null;
|
||||
chikouOffset?: number | null;
|
||||
user?: User | null;
|
||||
}
|
||||
|
||||
@@ -1072,6 +1085,7 @@ export interface IndicatorsResultBase {
|
||||
stdDev?: StdDevResult[] | null;
|
||||
superTrend?: SuperTrendResult[] | null;
|
||||
chandelierLong?: ChandelierResult[] | null;
|
||||
ichimoku?: IchimokuResult[] | null;
|
||||
}
|
||||
|
||||
export interface ResultBase {
|
||||
@@ -1148,6 +1162,14 @@ export interface SuperTrendResult extends ResultBase {
|
||||
lowerBand?: number | null;
|
||||
}
|
||||
|
||||
export interface IchimokuResult extends ResultBase {
|
||||
tenkanSen?: number | null;
|
||||
kijunSen?: number | null;
|
||||
senkouSpanA?: number | null;
|
||||
senkouSpanB?: number | null;
|
||||
chikouSpan?: number | null;
|
||||
}
|
||||
|
||||
export interface GetCandlesWithIndicatorsRequest {
|
||||
ticker?: Ticker;
|
||||
startDate?: Date;
|
||||
|
||||
@@ -105,6 +105,7 @@ const ALL_INDICATORS = [
|
||||
IndicatorType.DualEmaCross,
|
||||
IndicatorType.StochasticCross,
|
||||
IndicatorType.BollingerBandsPercentBMomentumBreakout,
|
||||
IndicatorType.IchimokuKumoTrend,
|
||||
]
|
||||
|
||||
// Indicator type to parameter mapping
|
||||
@@ -125,6 +126,7 @@ const INDICATOR_PARAM_MAPPING = {
|
||||
[IndicatorType.StochasticCross]: ['stochPeriods', 'signalPeriods', 'smoothPeriods', 'kFactor', 'dFactor'],
|
||||
[IndicatorType.Stc]: ['cyclePeriods', 'fastPeriods', 'slowPeriods'],
|
||||
[IndicatorType.LaggingStc]: ['cyclePeriods', 'fastPeriods', 'slowPeriods'],
|
||||
[IndicatorType.IchimokuKumoTrend]: ['tenkanPeriods', 'kijunPeriods', 'senkouBPeriods', 'offsetPeriods', 'senkouOffset', 'chikouOffset'],
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@@ -44,6 +44,7 @@ const ALL_INDICATORS = [
|
||||
IndicatorType.DualEmaCross,
|
||||
IndicatorType.StochasticCross,
|
||||
IndicatorType.BollingerBandsPercentBMomentumBreakout,
|
||||
IndicatorType.IchimokuKumoTrend,
|
||||
]
|
||||
|
||||
// Form Interface
|
||||
|
||||
@@ -22,6 +22,12 @@ interface IIndicatorFormInput {
|
||||
stochPeriods: number
|
||||
smoothPeriods: number
|
||||
cyclePeriods: number
|
||||
tenkanPeriods: number
|
||||
kijunPeriods: number
|
||||
senkouBPeriods: number
|
||||
offsetPeriods: number
|
||||
senkouOffset: number
|
||||
chikouOffset: number
|
||||
}
|
||||
|
||||
const IndicatorList: React.FC = () => {
|
||||
@@ -30,7 +36,16 @@ const IndicatorList: React.FC = () => {
|
||||
)
|
||||
const [indicators, setIndicators] = useState<IndicatorViewModel[]>([])
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const { register, handleSubmit } = useForm<IIndicatorFormInput>()
|
||||
const { register, handleSubmit } = useForm<IIndicatorFormInput>({
|
||||
defaultValues: {
|
||||
tenkanPeriods: 9,
|
||||
kijunPeriods: 26,
|
||||
senkouBPeriods: 52,
|
||||
offsetPeriods: 26,
|
||||
senkouOffset: 26,
|
||||
chikouOffset: 26
|
||||
}
|
||||
})
|
||||
const { apiUrl } = useApiUrlStore()
|
||||
const scenarioClient = new ScenarioClient({}, apiUrl)
|
||||
|
||||
@@ -47,7 +62,13 @@ const IndicatorList: React.FC = () => {
|
||||
form.multiplier,
|
||||
form.stochPeriods,
|
||||
form.smoothPeriods,
|
||||
form.cyclePeriods
|
||||
form.cyclePeriods,
|
||||
form.tenkanPeriods,
|
||||
form.kijunPeriods,
|
||||
form.senkouBPeriods,
|
||||
form.offsetPeriods,
|
||||
form.senkouOffset,
|
||||
form.chikouOffset
|
||||
)
|
||||
.then((indicator: IndicatorViewModel) => {
|
||||
t.update('success', 'Indicator created')
|
||||
@@ -497,6 +518,102 @@ const IndicatorList: React.FC = () => {
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{indicatorType == IndicatorType.IchimokuKumoTrend ? (
|
||||
<>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="tenkanPeriods" className="label mr-6">
|
||||
Tenkan Periods
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="9"
|
||||
className="input"
|
||||
{...register('tenkanPeriods')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="kijunPeriods" className="label mr-6">
|
||||
Kijun Periods
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="26"
|
||||
className="input"
|
||||
{...register('kijunPeriods')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="senkouBPeriods" className="label mr-6">
|
||||
Senkou B Periods
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="52"
|
||||
className="input"
|
||||
{...register('senkouBPeriods')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="offsetPeriods" className="label mr-6">
|
||||
Offset Periods
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="26"
|
||||
className="input"
|
||||
{...register('offsetPeriods')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="senkouOffset" className="label mr-6">
|
||||
Senkou Offset
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="26"
|
||||
className="input"
|
||||
{...register('senkouOffset')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="chikouOffset" className="label mr-6">
|
||||
Chikou Offset
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="26"
|
||||
className="input"
|
||||
{...register('chikouOffset')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<div className="modal-action">
|
||||
<button type="submit" className="btn">
|
||||
Build
|
||||
|
||||
@@ -22,6 +22,12 @@ interface IIndicatorFormInput {
|
||||
stochPeriods: number
|
||||
smoothPeriods: number
|
||||
cyclePeriods: number
|
||||
tenkanPeriods: number
|
||||
kijunPeriods: number
|
||||
senkouBPeriods: number
|
||||
offsetPeriods: number
|
||||
senkouOffset: number
|
||||
chikouOffset: number
|
||||
}
|
||||
|
||||
const IndicatorList: React.FC = () => {
|
||||
@@ -30,7 +36,16 @@ const IndicatorList: React.FC = () => {
|
||||
)
|
||||
const [indicators, setIndicators] = useState<Indicator[]>([])
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const { register, handleSubmit } = useForm<IIndicatorFormInput>()
|
||||
const { register, handleSubmit } = useForm<IIndicatorFormInput>({
|
||||
defaultValues: {
|
||||
tenkanPeriods: 9,
|
||||
kijunPeriods: 26,
|
||||
senkouBPeriods: 52,
|
||||
offsetPeriods: 26,
|
||||
senkouOffset: 26,
|
||||
chikouOffset: 26
|
||||
}
|
||||
})
|
||||
const { apiUrl } = useApiUrlStore()
|
||||
const scenarioClient = new ScenarioClient({}, apiUrl)
|
||||
|
||||
@@ -47,7 +62,13 @@ const IndicatorList: React.FC = () => {
|
||||
form.multiplier,
|
||||
form.stochPeriods,
|
||||
form.smoothPeriods,
|
||||
form.cyclePeriods
|
||||
form.cyclePeriods,
|
||||
form.tenkanPeriods,
|
||||
form.kijunPeriods,
|
||||
form.senkouBPeriods,
|
||||
form.offsetPeriods,
|
||||
form.senkouOffset,
|
||||
form.chikouOffset
|
||||
)
|
||||
.then((indicator: Indicator) => {
|
||||
t.update('success', 'Indicator created')
|
||||
@@ -413,6 +434,102 @@ const IndicatorList: React.FC = () => {
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{indicatorType == IndicatorType.IchimokuKumoTrend ? (
|
||||
<>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="tenkanPeriods" className="label mr-6">
|
||||
Tenkan Periods
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="9"
|
||||
className="input"
|
||||
{...register('tenkanPeriods')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="kijunPeriods" className="label mr-6">
|
||||
Kijun Periods
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="26"
|
||||
className="input"
|
||||
{...register('kijunPeriods')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="senkouBPeriods" className="label mr-6">
|
||||
Senkou B Periods
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="52"
|
||||
className="input"
|
||||
{...register('senkouBPeriods')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="offsetPeriods" className="label mr-6">
|
||||
Offset Periods
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="26"
|
||||
className="input"
|
||||
{...register('offsetPeriods')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="senkouOffset" className="label mr-6">
|
||||
Senkou Offset
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="26"
|
||||
className="input"
|
||||
{...register('senkouOffset')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="chikouOffset" className="label mr-6">
|
||||
Chikou Offset
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="26"
|
||||
className="input"
|
||||
{...register('chikouOffset')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<div className="modal-action">
|
||||
<button type="submit" className="btn">
|
||||
Build
|
||||
|
||||
Reference in New Issue
Block a user