更新日:2024/8/24
JSTraderカスタムインジケーターサンプル
export default [
(): ItemIndicator<
{
period: number;
lineColor: string;
lineWidth: number;
lineDash: number[];
ohlc?: "open" | "high" | "low" | "close";
},
{ smaBuffer: IndicatorBuffer }
> => ({
type: "i",
name: "sample.SMA",
onInit() {
const { lineColor, lineWidth, lineDash } = this.params;
this.smaBuffer = this.addLineBuffer({
lineColor,
lineWidth,
lineDash,
});
this.shortName = "SMA";
this.onChartChange = ({ index, opens, highs, lows, closes }) => {
const period = this.params.period;
const ohlc = this.params.ohlc;
const buffer =
ohlc === "open"
? opens
: ohlc === "high"
? highs
: ohlc === "low"
? lows
: closes;
buffer.sma(this.smaBuffer, period, index);
};
this.getDisplayData = (index) => {
return { rate: this.smaBuffer.get(index) };
};
},
params: {
period: 25,
lineColor: "red",
lineWidth: 2,
lineDash: [3, 3],
ohlc: "close",
},
}),
(): ItemIndicator<
{
period: number;
lineColor: string;
lineWidth: number;
lineDash: number[];
ohlc?: "open" | "high" | "low" | "close";
},
{ emaBuffer: IndicatorBuffer }
> => ({
type: "i",
name: "sample.EMA",
onInit() {
const { lineColor, lineWidth, lineDash } = this.params;
const emaBuffer = (this.emaBuffer = this.addLineBuffer({
lineColor,
lineWidth,
lineDash,
}));
this.shortName = "EMA";
this.onChartChange = ({
index,
times,
opens,
highs,
lows,
closes,
spreads,
}) => {
const period = this.params.period;
const ohlc = this.params.ohlc;
const buffer =
ohlc === "open"
? opens
: ohlc === "high"
? highs
: ohlc === "low"
? lows
: closes;
buffer.ema(emaBuffer, period, index);
};
this.getDisplayData = (index) => {
return { ema: emaBuffer.get(index) } as const;
};
},
params: {
period: 25,
lineColor: "green",
lineWidth: 2,
lineDash: [3, 3],
ohlc: "close",
},
}),
(): ContainerIndicator<
{
initialHeight: number | string;
upColor: string;
sameColor: string;
downColor: string;
},
{
candleStickBuffer: [
IndicatorBuffer,
IndicatorBuffer,
IndicatorBuffer,
IndicatorBuffer,
];
}
> => ({
type: "c",
name: "sample.HeikinAshi",
onInit() {
const { initialHeight, upColor, sameColor, downColor } = this.params;
this.initialHeight = initialHeight;
const [openBuffer, highBuffer, lowBuffer, closeBuffer] =
(this.candleStickBuffer = this.addCandleStickBuffer([
upColor,
sameColor,
downColor,
]));
this.shortName = "heikin";
this.isShowDefaultRoundNumber = true;
this.onChartChange = ({
index,
times,
opens,
highs,
lows,
closes,
spreads,
}) => {
const preOpen = opens.get(index - 1),
preClose = closes.get(index - 1);
openBuffer.set(index, (preOpen + preClose) / 2);
highBuffer.set(index, highs.get(index));
lowBuffer.set(index, lows.get(index));
closeBuffer.set(
index,
(opens.get(index) +
highs.get(index) +
lows.get(index) +
closes.get(index)) /
4,
);
};
this.getDisplayData = (index) => {
return {
open: openBuffer.get(index),
close: closeBuffer.get(index),
};
};
},
params: {
upColor: "blue",
sameColor: "black",
downColor: "red",
initialHeight: "25%",
},
}),
(): ContainerIndicator<
{
fastEmaPeriod: number;
slowEmaPeriod: number;
signalSmaPeriod: number;
macdColor: string;
signalColor: string;
osciColor: string;
initialHeight: string | number;
},
{
macdBuffer: IndicatorBuffer;
signalBuffer: IndicatorBuffer;
osciBuffer: IndicatorBuffer;
}
> => ({
type: "c",
name: "sample.MACD",
onInit() {
const { initialHeight, osciColor, macdColor, signalColor } = this.params;
this.initialHeight = initialHeight;
const osciBuffer = (this.osciBuffer = this.addHistgramBuffer({
backgroundColor: osciColor,
baseValue: 0,
}));
const fastEmaBuffer = this.addWorkBuffer();
const slowEmaBuffer = this.addWorkBuffer();
const macdBuffer = (this.macdBuffer = this.addLineBuffer({
lineColor: macdColor,
lineWidth: 2,
}));
const signalBuffer = (this.signalBuffer = this.addLineBuffer({
lineColor: signalColor,
lineWidth: 2,
}));
this.shortName = "MACD";
this.digit = 0;
this.addPercentLine(0, "darkgray");
this.onChartChange = ({
index,
times,
opens,
highs,
lows,
closes,
spreads,
}) => {
const { fastEmaPeriod, slowEmaPeriod, signalSmaPeriod } = this.params;
closes.ema(fastEmaBuffer, fastEmaPeriod, index);
closes.ema(slowEmaBuffer, slowEmaPeriod, index);
const macdVal = fastEmaBuffer.get(index) - slowEmaBuffer.get(index);
macdBuffer.set(index, macdVal);
const signalVal = macdBuffer.ema(
signalBuffer,
signalSmaPeriod,
index,
slowEmaPeriod,
);
osciBuffer.set(index, macdVal - signalVal);
};
this.getDisplayData = (index) => {
return {
macd: macdBuffer.get(index),
signal: signalBuffer.get(index),
osci: osciBuffer.get(index),
};
};
},
params: {
fastEmaPeriod: 12,
slowEmaPeriod: 26,
signalSmaPeriod: 9,
macdColor: "green",
signalColor: "cyan",
osciColor: "gray",
initialHeight: "25%",
},
}),
(): ContainerIndicator<
{
periods: number[];
colors: string[];
initialHeight: number | string;
},
{
kBuffer: IndicatorBuffer;
dBuffer: IndicatorBuffer;
sdBuffer: IndicatorBuffer;
}
> => ({
type: "c",
name: "sample.Stochastics",
onInit() {
const {
initialHeight,
colors: [kColor, dColor, sdColor],
} = this.params;
this.initialHeight = initialHeight;
const kBuffer = (this.kBuffer = this.addLineBuffer({
lineColor: kColor,
}));
const dBuffer = (this.dBuffer = this.addLineBuffer({
lineColor: dColor,
}));
const sdBuffer = (this.sdBuffer = this.addLineBuffer({
lineColor: sdColor,
}));
const numeratorBuffer = this.addWorkBuffer();
const denominatorBuffer = this.addWorkBuffer();
this.shortName = "stochastics";
this.addPercentLine(80, "darkgray");
this.addPercentLine(20, "darkgray");
this.digit = 0;
this.onChartChange = ({
index,
times,
opens,
highs,
lows,
closes,
spreads,
}) => {
const [kPeriod, dPeriod, sdPeriod] = this.params.periods;
const lowest = lows.min(index - kPeriod + 1, index),
highest = highs.max(index - kPeriod + 1, index),
close = closes.get(index),
num = close - lowest,
denom = highest - lowest;
numeratorBuffer.set(index, num);
denominatorBuffer.set(index, denom);
const val = (num / denom) * 100;
kBuffer.set(index, val);
const sumNumerator = numeratorBuffer.sum(index - dPeriod + 1, index),
sumDenominator = denominatorBuffer.sum(index - dPeriod + 1, index);
dBuffer.set(index, (sumNumerator / sumDenominator) * 100);
const avg = dBuffer.avg(index - sdPeriod + 1, index);
sdBuffer.set(index, avg);
};
this.getDisplayData = (index) => {
return {
k: kBuffer.get(index),
d: dBuffer.get(index),
sd: sdBuffer.get(index),
};
};
this.getMin = () => {
return 0;
};
this.getMax = () => {
return 100;
};
},
params: {
periods: [14, 3, 3],
colors: ["aqua", "green", "gold"],
initialHeight: "25%",
},
}),
(): ContainerIndicator<
{
period: number;
lineColor: string;
initialHeight: number | string;
},
{ rsiBuffer: IndicatorBuffer }
> => ({
type: "c",
name: "sample.RSI",
onInit() {
const { initialHeight, lineColor } = this.params;
this.initialHeight = initialHeight;
const diffBuffer = this.addWorkBuffer();
const rsiBuffer = (this.rsiBuffer = this.addLineBuffer({ lineColor }));
this.addPercentLine(70, "darkgray");
this.addPercentLine(30, "darkgray");
this.digit = 0;
this.onChartChange = ({
index,
times,
opens,
highs,
lows,
closes,
spreads,
}) => {
const period = this.params.period;
const diff = closes.get(index) - closes.get(index - 1);
diffBuffer.set(index, diff);
let sumGain = 0,
sumLoss = 0;
for (let i = index - period + 1; i <= index; i++) {
const diff = diffBuffer.get(i);
if (diff > 0) {
sumGain += diff;
} else if (diff <= 0) {
sumLoss -= diff;
} else {
(sumGain = NaN), (sumLoss = NaN);
break;
}
}
const avgGain = sumGain / period,
avgLoss = Math.abs(sumLoss) / period;
const rsi =
avgLoss === 0
? 100
: avgGain === 0
? 0
: 100 - 100 / (1 + avgGain / avgLoss);
rsiBuffer.set(index, rsi);
};
this.getDisplayData = (index) => {
return { rate: rsiBuffer.get(index) };
};
this.getMin = () => {
return 0;
};
this.getMax = () => {
return 100;
};
},
params: {
period: 14,
lineColor: "purple",
initialHeight: "25%",
},
}),
(): ItemIndicator<
{
shortPeriods: number[];
longPeriods: number[];
shortColor: string;
longColor: string;
},
{
shortEmaBuffers: IndicatorBuffer[];
longEmaBuffers: IndicatorBuffer[];
}
> => ({
type: "i",
name: "sample.GMMA",
onInit() {
this.shortName = "GMMA";
const params = this.params;
const _this = this;
const shortEmas = params.shortPeriods.map(function (period) {
return _this.addItemIndicator("sample.EMA", {
period: period,
lineColor: params.shortColor,
lineDash: [],
lineWidth: 1,
});
});
const longEmas = params.longPeriods.map(function (period) {
return _this.addItemIndicator("sample.EMA", {
period: period,
lineColor: params.longColor,
lineDash: [],
lineWidth: 1,
});
});
this.shortEmaBuffers = shortEmas.map((x) => x.emaBuffer);
this.longEmaBuffers = longEmas.map((x) => x.emaBuffer);
this.getDisplayData = (index) => {
return [...shortEmas, ...longEmas].reduce(
(acc, ema) => {
acc[ema.params.period] = Object.values(
ema.getDisplayData(index),
)[0];
return acc;
},
{} as Record<string, any>,
);
};
},
params: {
shortPeriods: [3, 5, 8, 10, 12, 15],
longPeriods: [30, 35, 40, 45, 50, 60],
shortColor: "cyan",
longColor: "pink",
},
}),
(): ItemIndicator<
{
fast: { period: number; lineColor: string };
slow: { period: number; lineColor: string };
},
{}
> => ({
type: "i",
name: "sample.sample.SmaCrossSignal",
onInit() {
this.zIndex = 1;
const params = this.params;
const origParams = IndicatorUtil.getParameter("sample.SMA");
const fastParams = { ...origParams, ...params.fast, ...{ zIndex: 0 } };
const slowParams = { ...origParams, ...params.slow, ...{ zIndex: 0 } };
const fastSMA = this.addItemIndicator("sample.SMA", fastParams);
const slowSMA = this.addItemIndicator("sample.SMA", slowParams);
const smaCrossSignalBuffer = this.addTextBuffer({
arrow: false,
backgroundColor: "white",
borderColor: "black",
borderWidth: 0,
color: "black",
fontFamily:
"Font Awesome 6 Free" /* Currently the only available web font is Font Awesome 6 Free */,
fontSize: { min: 20, max: 30 },
position: "center",
});
const entryPointTextBuffer = this.addTextBuffer({
arrow: true,
backgroundColor: "white",
borderColor: "black",
color: "red",
fontSize: { min: 20, max: 30 },
padding: 5,
});
this.onChartChange = ({
index,
times,
opens,
highs,
lows,
closes,
spreads,
isBarChanged,
}) => {
const fastBuffer = fastSMA.smaBuffer,
slowBuffer = slowSMA.smaBuffer;
if (isBarChanged) {
if (
fastBuffer.get(index - 2) <= slowBuffer.get(index - 2) &&
fastBuffer.get(index - 1) > slowBuffer.get(index - 1)
) {
smaCrossSignalBuffer.set(index - 1, lows.get(index - 1), {
position: "bottom",
text: 0xf0aa /* circle-arrow-up */,
});
entryPointTextBuffer.set(index, opens.get(index), {
position: "left",
text: "Buy",
});
}
if (
fastBuffer.get(index - 2) >= slowBuffer.get(index - 2) &&
fastBuffer.get(index - 1) < slowBuffer.get(index - 1)
) {
smaCrossSignalBuffer.set(index - 1, highs.get(index - 1), {
position: "top",
text: 0xf0ab /* circle-arrow-down */,
});
entryPointTextBuffer.set(index, opens.get(index), {
position: "left",
text: "Sell",
});
}
}
};
},
params: {
fast: { period: 10, lineColor: "lime" },
slow: { period: 30, lineColor: "cyan" },
},
}),
]