カテゴリー: iOS

Swift Chartsライブラリでボリンジャーバンドを描画してみる。

はじめに

こんにちはsuzukiです。引き続きChartsを使いボリンジャーバンドの描画に挑戦します。
前回記事で移動平均線を描画する際に少し詳しくChartsライブラリの説明をしています。よければご覧ください。

ボリンジャーバンドとは

ボリンジャーバンドはローソク足を分析する際の手法です。詳しい内容自体はリンクを参照ください。
今回プログラムでは下記の三点と一部のデータだけ画面に表示するということを行っていきたいと思います。

  • 標準偏差σを求める
  • 移動平均線に±σを行いグラフのデータを作成する
  • CombineChartで描画を行う

ライブラリの導入

前回記事同様にChartsライブラリをPodで導入します。

描画の準備

次にStoryBoardでチャートの描画範囲を決めましょう。

  • CombinedChartViewを追加
  • 上下左右に制約を追加
  • CombinedChartViewを関連付け

ボリンジャーバンドを描画する

それでは実際にボリンジャーバンドを描画しましょう。
完成予定

CombinedChartViewの設定

CombineChartViewにはこの前とほとんど同じなのですが、新たにデータ数を増やす影響もありX軸の表示数に制限を行います。
chart.setVisibleXRangeMaximum(30)
chart.setVisibleXRangeMinimum(5)
またスワイプの動作を行うためdragEnabledをtrueに変更します
chart.dragEnabled = true

//  複合チャートの描画
    func setupCombineChart(_ chart: CombinedChartView, data: CombinedChartData){
        //     dragを有効化
        chart.dragEnabled = true
        chart.setScaleEnabled(true)
        chart.pinchZoomEnabled = true
        //      legendの設定
        chart.legend.horizontalAlignment = .left
        chart.legend.verticalAlignment = .bottom
        chart.legend.orientation = .horizontal
        chart.legend.drawInside = false
        chart.legend.font = UIFont(name: "HelveticaNeue-Light", size: 10)!
        //      左の目盛りの設定
        chart.leftAxis.labelFont = UIFont(name: "HelveticaNeue-Light", size: 10)!
        chart.leftAxis.spaceTop = 0.3
        chart.leftAxis.spaceBottom = 0.3
        chart.leftAxis.axisMinimum = 90
        //
        chart.rightAxis.enabled = false
        
        chart.xAxis.labelPosition = .bottom
        chart.xAxis.labelFont = UIFont(name: "HelveticaNeue-Light", size: 10)!
        chart.xAxis.axisMaximum = data.xMax + 0.25
        chart.data = data
        //チャートにデータ設定を行った後に設定
        chart.setVisibleXRangeMaximum(30)
        chart.setVisibleXRangeMinimum(5)
    }

CombinedChartView用のデータ作成

今回はボリンジャーバンドを作成するためのデータを作成します。
ローソク足用のデータは移動平均線と同様のデータ
var endPoints: [Double] = []
上記に加えて、移動平均線は5日としてデータ作成したのですが、ボリンジャーバンドは期間が20or25と書いてあったため下記を宣言します。
//移動平均線の計算、および標準偏差を求める際の期間とりあえず20を設定
let periodCount = 20

宣言したendPointsにキャンドルデータの作成のロジック部分で終値を保存します。

    func generateCandleData(_ count: Int, range: UInt32) -> CandleChartData {
        //endPointsを初期化ローソク足のチャートでも読んでいるため
        endPoints = []
        let yVals1 = (0..<count).map { (i) -> CandleChartDataEntry in
            let mult = range + 1
            let val = Double(arc4random_uniform(40) + mult)
            let high = Double(arc4random_uniform(9) + 8)
            let low = Double(arc4random_uniform(9) + 8)
            let open = Double(arc4random_uniform(6) + 1)
            let close = Double(arc4random_uniform(6) + 1)
            
            let even = i % 2 == 0
            //終値のデータを保存
            endPoints.append( even ? val - close : val + close)
            //ローソク足用のデータ作成
            return CandleChartDataEntry(x: Double(i), shadowH: val + high, shadowL: val - low, open: even ? val + open : val - open, close: even ? val - close : val + close, icon: nil)
        }

続いてボリンジャーバンド用のデータです。
移動平均線は一つの折れ線でしたがボリンジャーバンドは下記の5つの折れ線です。

  • アッパーバンド2:単純移動平均線+2標準偏差(σ)
  • アッパーバンド1:単純移動平均線+1標準偏差(σ)
  • ミッドバンド:単純移動平均線
  • ロワーバンド1:単純移動平均線-1標準偏差(σ)
  • ロワーバンド2:単純移動平均線-2標準偏差(σ)

前回と同じようなコードだととても縦長になってしまうため。下記の関数を作成します。

//ChartDataEntry,ラベルの文字列、線の色を受け取り LineChartDataSetを返却する関数
    func createDataSet(entry: [ChartDataEntry] , label: String ,color: UIColor) -> LineChartDataSet{
        let dataSet = LineChartDataSet(values: entry, label: label)
        dataSet.lineWidth = 1.75
        dataSet.setColor(color)
        dataSet.drawValuesEnabled = false
        dataSet.drawCirclesEnabled = false
        return dataSet
    }

続いてendPointからボリンジャーバンド用にデータを作成します。
引数でendPointsを明示的に渡すようにしました。
sliceでarrayを作ったのでそのまま書いていますが、標準偏差sigmaを求める関数作った方がシンプルに見えるかもしれません。

func bolingerBandData(endPoints: [Double]) -> LineChartData
        //アッパーバンド2=単純移動平均線+2標準偏差(σ)
        var upperBand2Entry: [ChartDataEntry] = []
        //アッパーバンド1=単純移動平均線+1標準偏差(σ)
        var upperBand1Entry: [ChartDataEntry] = []
        //ミッドバンド=単純移動平均線
        var midBandEntry: [ChartDataEntry] = []
        //ロワーバンド1=単純移動平均線-1標準偏差(σ)
        var lowerBand1Entry: [ChartDataEntry] = []
        //ロワーバンド2=単純移動平均線-2標準偏差(σ)
        var lowerBand2Entry: [ChartDataEntry] = []
        
        endPoints.enumerated().forEach { (i, data) in
            //最初の2件と終わりの2件はデータを表示しない
            guard i >= periodCount - 1 else{
                return
            }
            //期間中のデータ
            let array = endPoints[i - (periodCount - 1) ... i]
            //単純移動平均線用のデータ 
            let val = array.reduce(0, +) / Double(periodCount)
            
            ///標準偏差σを求める計算式
            //期間毎価格の合計の自乗の合計
            let left = array.map{pow($0,2)}.reduce(0, +) * Double(periodCount)
            //価格の合計の自乗
            let right = pow(array.reduce(0, +),2)
            //期間*(期間-1)
            let under = Double(periodCount * (periodCount - 1))
            //標準偏差 
            let sigma = sqrt((left - right) / under)

            //移動平均線に±σを行いグラフのデータを作成する
            upperBand2Entry.append(ChartDataEntry(x: Double(i), y: val + (sigma*2)))
            upperBand1Entry.append(ChartDataEntry(x: Double(i), y: val + sigma))
            midBandEntry.append(ChartDataEntry(x: Double(i), y: val))
            lowerBand1Entry.append(ChartDataEntry(x: Double(i), y: val - sigma))
            lowerBand2Entry.append(ChartDataEntry(x: Double(i), y: val - (sigma*2)))
        }
        return LineChartData(dataSets: [
            createDataSet(entry: upperBand2Entry, label: "upper2", color: .red),
            createDataSet(entry: upperBand1Entry, label: "upper1", color: .blue),
            createDataSet(entry: midBandEntry, label: "mid", color: .black),
            createDataSet(entry: lowerBand1Entry, label: "lower1", color: .blue),
            createDataSet(entry: lowerBand2Entry, label: "lower2", color: .red)])
    }

CombinedChartViewに描画

最後に下記で描画します。ローソク足の個数はとりあえず200で描画しています。

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        //CombineChartで描画を行う
        let cobinedData = CombinedChartData()
        cobinedData.candleData = generateCandleData(200, range: 100)
        cobinedData.lineData = bolingerBandData(endPoints: endPoints)
        setupCombineChart(combinedChartView,data: cobinedData)
    }

さいごに

テクニカルチャートの要件があり勉強中ですが、実際にテクニカルチャートをもとに取引をした事がありません。
テクニカルチャートをもとに取引を行って重要性を学んでみたいですね。取引額は控えめで!
それでは最後までありがとうございました。今度はKotlinか一目均衡表を学んでみようと思います。

おすすめ書籍

    

— NORMAL —
suzuki

シェア
執筆者:
suzuki
タグ: Swift

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

2週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

4週間 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前