はじめに
こんにちはsuzukiです。引き続きChartsを使いボリンジャーバンドの描画に挑戦します。
前回記事で移動平均線を描画する際に少し詳しくChartsライブラリの説明をしています。よければご覧ください。
ボリンジャーバンドとは
ボリンジャーバンドはローソク足を分析する際の手法です。詳しい内容自体はリンクを参照ください。
今回プログラムでは下記の三点と一部のデータだけ画面に表示するということを行っていきたいと思います。
- 標準偏差σを求める
- 移動平均線に±σを行いグラフのデータを作成する
- CombineChartで描画を行う
ライブラリの導入
前回記事同様にChartsライブラリをPodで導入します。
描画の準備
次にStoryBoardでチャートの描画範囲を決めましょう。
- CombinedChartViewを追加
- 上下左右に制約を追加
- CombinedChartViewを関連付け
ボリンジャーバンドを描画する
それでは実際にボリンジャーバンドを描画しましょう。
完成予定
CombinedChartViewの設定
CombineChartViewにはこの前とほとんど同じなのですが、新たにデータ数を増やす影響もありX軸の表示数に制限を行います。chart.setVisibleXRangeMaximum(30)
chart.setVisibleXRangeMinimum(5)
またスワイプの動作を行うためdragEnabledをtrueに変更しますchart.dragEnabled = true
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // 複合チャートの描画 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にキャンドルデータの作成のロジック部分で終値を保存します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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) //ローソク足用のデータ作成 returnCandleChartDataEntry(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標準偏差(σ)
前回と同じようなコードだととても縦長になってしまうため。下記の関数を作成します。
1 2 3 4 5 6 7 8 9 | //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 returndataSet } |
続いてendPointからボリンジャーバンド用にデータを作成します。
引数でendPointsを明示的に渡すようにしました。
sliceでarrayを作ったのでそのまま書いていますが、標準偏差sigmaを求める関数作った方がシンプルに見えるかもしれません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | func bolingerBandData(endPoints:[Double])->LineChartData //アッパーバンド2=単純移動平均線+2標準偏差(σ) varupperBand2Entry:[ChartDataEntry]=[] //アッパーバンド1=単純移動平均線+1標準偏差(σ) varupperBand1Entry:[ChartDataEntry]=[] //ミッドバンド=単純移動平均線 varmidBandEntry:[ChartDataEntry]=[] //ロワーバンド1=単純移動平均線-1標準偏差(σ) varlowerBand1Entry:[ChartDataEntry]=[] //ロワーバンド2=単純移動平均線-2標準偏差(σ) varlowerBand2Entry:[ChartDataEntry]=[] endPoints.enumerated().forEach{(i,data)in //最初の2件と終わりの2件はデータを表示しない guardi>=periodCount-1else{ 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))) } returnLineChartData(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で描画しています。
1 2 3 4 5 6 7 8 9 | 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か一目均衡表を学んでみようと思います。