文字を表示する


概要

TextBufferを使うとインジケーターに文字を表示することができます。

TextBufferのオプションは次の2箇所で設定可能です。同じ値をセットした場合、後にセットした値が有効になります。

  • onInitイベント内のaddTextBuffer呼び出し時(fontSizeはこの時のみ設定可能)
  • onChartChangeイベント内でのsetメソッドの第3引数
キー 説明
position 指定した座標のどの位置に表示するか
center(デフォルト),top,right,left,bottom
arrow 吹き出しの矢印を表示するかどうか。position:centerの時はこの値にかかわらず常に非表示
backgroundColor 背景色
borderColor 線色
borderWidth 線の太さ
color 文字色
fontFamily フォントファミリー。2023年8月現在、WEBフォントで設定可能なものはFont Awesome 6 Freeのみ
fontSize 未指定:チャートの太さと同じ
数値:固定値
min,max:最小値、最大値を設定
text 表示するテキスト。文字または文字コード(数値)で設定してください。Font Awesome 6 Freeは文字コード(数値)のみ設定可能です
padding borderとtextの間隔。2023年8月時点、4辺ごとに異なる値を設定することはできません

移動平均がクロスしたタイミングを表示する

このサンプルを実行する前に、tutor.SMAを登録してください 参照:単純移動平均を作る
tutor.SMAのコード
export default (): ItemIndicator<
    {
        period: number
        lineColor: string
        lineWidth: number
        lineDash: number[]
        targetOhlc: 'opens' | 'highs' | 'lows' | 'closes' 
    }, {
        smaBuffer: IndicatorBuffer
    }

> => {
    return {
        type: 'i',
        name: "tutor.SMA",
        onInit() {
            const { period, targetOhlc, ...smaParams } = this.params
            const smaBuffer = this.smaBuffer = this.addLineBuffer(smaParams)
            this.shortName = 'SMA'
            this.onChartChange = ({ index, ...rest }) => {
                const targetBuffer = rest[targetOhlc] 
                if (!targetBuffer) {
                    throw new Error(`${targetOhlc}にはopens,highs,lows,closesを指定してください`) 
                }
                targetBuffer.sma(smaBuffer, period, index)
            }
            this.getDisplayData = (index) => {
                return {
                    sma: smaBuffer.get(index)
                }
            }
        },
        params: {
            period: 25,
            lineColor: 'red',
            lineWidth: 2,
            lineDash: [3, 3],
            targetOhlc: 'closes'
        }
    }
}
               
export default (): ItemIndicator<{
    fast: {
        period: number,
        lineColor: string
    },
    slow: {
        period: number,
        lineColor: string
    }
}> => {
    return {
        type: "i",
        name: "tutor.SmaCrossSignal1",
        onInit() {
            const params = this.params;
            const origParams = IndicatorUtil.getParameter("tutor.SMA") //1
            const fastParams = { ...origParams, ...params.fast }
            const slowParams = { ...origParams, ...params.slow }
            const fastBuffer = this.addItemIndicator("tutor.SMA", fastParams).smaBuffer
            const slowBuffer = this.addItemIndicator("tutor.SMA", slowParams).smaBuffer
            const smaCrossSignalBuffer = this.addTextBuffer({ //2
                arrow: false,
                backgroundColor: 'white',
                borderColor: 'black',
                borderWidth: 0,
                color: 'black',
                fontFamily: 'Font Awesome 6 Free',
                fontSize: { min: 20, max: 30 },
            })
            this.onChartChange = ({ index, isBarChanged }) => {
                if (isBarChanged) { //3
                    if (fastBuffer.get(index - 2) <= slowBuffer.get(index - 2) //4
                        && fastBuffer.get(index - 1) > slowBuffer.get(index - 1)) {
                        smaCrossSignalBuffer.set(index - 1, fastBuffer.get(index - 1), { //5
                            position: 'bottom',
                            text: 0xf0aa // arrow-up 
                        })
                    }
                    if (fastBuffer.get(index - 2) >= slowBuffer.get(index - 2)
                        && fastBuffer.get(index - 1) < slowBuffer.get(index - 1)) {
                        smaCrossSignalBuffer.set(index - 1, fastBuffer.get(index - 1), {
                            position: 'top',
                            text: 0xf0ab // arrow-down 
                        })
                    }
                }
            }
        },
        params: {
            fast: {
                period: 10,
                lineColor: "lime"
            },
            slow: {
                period: 30,
                lineColor: "cyan"
            }
        }
    }
}
               
1 既存のインジケーターのパラメータを取得しています。
2 TextBufferを追加しています。
3 isBarChangedは時間足が切り替わるタイミングでのみtrueになります。
4 2本前のバーと1本前のバーを比較してゴールデンクロスの判定をしています。
5

TextBufferに値をセットしています。TextBufferのsetは他の第3引数に概要にあるオプションを設定することができます。

ここでは、現時点よりも過去のバーにテキストを設定しています。ストラテジーから参照する場合、ストラテジーは過去に戻ることはできないのでこのシグナルをもとに売買することはできません。

売買のタイミングも表示する

上記でゴールデンクロス、デッドクロスのタイミングを矢印で表示しましたが、実際の売買は次のバーの始値で行いたいため、その表示も追加します。

export default (): ItemIndicator<{
    fast: {
        period: number,
        lineColor: string
    },
    slow: {
        period: number,
        lineColor: string
    }
}> => {
    return {
        type: "i",
        name: "tutor.SmaCrossSignal2",
        onInit() {
            const params = this.params;
            const origParams = IndicatorUtil.getParameter("tutor.SMA")
            const fastParams = { ...origParams, ...params.fast }
            const slowParams = { ...origParams, ...params.slow }
            const fastBuffer = this.addItemIndicator("tutor.SMA", fastParams).smaBuffer
            const slowBuffer = this.addItemIndicator("tutor.SMA", slowParams).smaBuffer
            const smaCrossSignalBuffer = this.addTextBuffer({
                arrow: false,
                backgroundColor: 'white',
                borderColor: 'black',
                borderWidth: 0,
                color: 'black',
                fontFamily: 'Font Awesome 6 Free',
                fontSize: { min: 20, max: 30 },
            })
            const entryPointTextBuffer = this.addTextBuffer({ //1
                arrow: true,
                backgroundColor: 'white',
                borderColor: 'black',
                color: 'red',
                fontSize: { min: 20, max: 30 },
                padding: 5
            })
            this.onChartChange = ({ index, opens, isBarChanged }) => {
                if (isBarChanged) {
                    if (fastBuffer.get(index - 2) <= slowBuffer.get(index - 2)
                        && fastBuffer.get(index - 1) > slowBuffer.get(index - 1)) {
                        smaCrossSignalBuffer.set(index - 1, fastBuffer.get(index - 1), {
                            position: 'bottom',
                            text: 0xf0aa // 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, fastBuffer.get(index - 1), {
                            position: 'top',
                            text: 0xf0ab // arrow-down 
                        })
                        entryPointTextBuffer.set(index, opens.get(index), {
                            position: 'left',
                            text: 'Sell'
                        })
                    }
                }
            }
        },
        params: {
            fast: {
                period: 10,
                lineColor: "lime"
            },
            slow: {
                period: 30,
                lineColor: "cyan"
            }
        }
    }
}
               
1 先ほどとは別のTextBufferをパラメーターを変えて追加しています。

addItemIndicatorで追加したインジケーターの描画順序を設定する

上記でおおよそ完成しましたが、アローの上に移動平均線が表示される不具合があります

現状 理想

これは、デフォルトでは初めに自信のインジケーターが描画され、その後でaddItemIndicatorで追加したインジケーターが描画されるためです。

この順序を制御するには自信のインジケーターとaddItemIndicatorの引数にzIndexを設定します。

export default (): ItemIndicator<{
    fast: {
        period: number,
        lineColor: string
    },
    slow: {
        period: number,
        lineColor: string
    }
}> => {
    return {
        type: "i",
        name: "tutor.SmaCrossSignal3",
        onInit() {
            this.zIndex = 1; //1
            const params = this.params;
            const origParams = IndicatorUtil.getParameter("tutor.SMA")
            const fastParams = { ...origParams, ...params.fast }
            const slowParams = { ...origParams, ...params.slow }
            const fastBuffer = this.addItemIndicator("tutor.SMA", { ...fastParams, ...{ zIndex: 0 } }).smaBuffer
            const slowBuffer = this.addItemIndicator("tutor.SMA", { ...slowParams, ...{ zIndex: 0 } }).smaBuffer
            const smaCrossSignalBuffer = this.addTextBuffer({
                arrow: false,
                backgroundColor: 'white',
                borderColor: 'black',
                borderWidth: 0,
                color: 'black',
                fontFamily: 'Font Awesome 6 Free',
                fontSize: { min: 20, max: 30 },
            })
            const entryPointTextBuffer = this.addTextBuffer({
                arrow: true,
                backgroundColor: 'white',
                borderColor: 'black',
                color: 'red',
                fontSize: { min: 20, max: 30 },
                padding: 5
            })
            this.onChartChange = ({ index, opens, isBarChanged }) => {
                if (isBarChanged) {
                    if (fastBuffer.get(index - 2) <= slowBuffer.get(index - 2)
                        && fastBuffer.get(index - 1) > slowBuffer.get(index - 1)) {
                        smaCrossSignalBuffer.set(index - 1, fastBuffer.get(index - 1), {
                            position: 'bottom',
                            text: 0xf0aa // 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, fastBuffer.get(index - 1), {
                            position: 'top',
                            text: 0xf0ab // arrow-down 
                        })
                        entryPointTextBuffer.set(index, opens.get(index), {
                            position: 'left',
                            text: 'Sell'
                        })
                    }
                }
            }
        },
        params: {
            fast: {
                period: 10,
                lineColor: "lime"
            },
            slow: {
                period: 30,
                lineColor: "cyan"
            }
        }
    }
}
               
1 自信のzIndexを1に設定しデフォルトは0よりも前に表示されるようにしています。
2

addItemIndicatorの第2引数にzIndexを設定すると呼び出すアイテムインジケーターのzIndexを上書きします。

ストラテジーで型情報を利用できるようにする

ストラテジーのチュートリアルでこのページのコードを使って売買を行います。ストラテジーからentryPointTextBufferを参照するため型情報を公開しておきます。

export default (): ItemIndicator<{
    fast: {
        period: number,
        lineColor: string
    },
    slow: {
        period: number,
        lineColor: string
    }
}, {
    entryPointTextBuffer: TextBuffer //1
}> => {
    return {
        type: "i",
        name: "tutor.SmaCrossSignal",
        onInit() {
            this.zIndex = 1; 
            const params = this.params;
            const origParams = IndicatorUtil.getParameter("tutor.SMA")
            const fastParams = { ...origParams, ...params.fast }
            const slowParams = { ...origParams, ...params.slow }
            const fastBuffer = this.addItemIndicator("tutor.SMA", { ...fastParams, ...{ zIndex: 0 } }).smaBuffer
            const slowBuffer = this.addItemIndicator("tutor.SMA", { ...slowParams, ...{ zIndex: 0 } }).smaBuffer
            const smaCrossSignalBuffer = this.addTextBuffer({
                arrow: false,
                backgroundColor: 'white',
                borderColor: 'black',
                borderWidth: 0,
                color: 'black',
                fontFamily: 'Font Awesome 6 Free',
                fontSize: { min: 20, max: 30 },
            })
            const entryPointTextBuffer = this.entryPointTextBuffer = this.addTextBuffer({ //2
                arrow: true,
                backgroundColor: 'white',
                borderColor: 'black',
                color: 'red',
                fontSize: { min: 20, max: 30 },
                padding: 5
            })
            this.onChartChange = ({ index, opens, isBarChanged }) => {
                if (isBarChanged) {
                    if (fastBuffer.get(index - 2) <= slowBuffer.get(index - 2)
                        && fastBuffer.get(index - 1) > slowBuffer.get(index - 1)) {
                        smaCrossSignalBuffer.set(index - 1, fastBuffer.get(index - 1), {
                            position: 'bottom',
                            text: 0xf0aa // 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, fastBuffer.get(index - 1), {
                            position: 'top',
                            text: 0xf0ab // arrow-down 
                        })
                        entryPointTextBuffer.set(index, opens.get(index), {
                            position: 'left',
                            text: 'Sell'
                        })
                    }
                }
            }
        },
        params: {
            fast: {
                period: 10,
                lineColor: "lime"
            },
            slow: {
                period: 30,
                lineColor: "cyan"
            }
        }
    }
}
                   
1 ItemIndicator型の第2型引数に公開する型をしていしています
2

thisに参照を設定しています