My question is two fold but the logic may be similar.
I have a simple candlestick chart with two different indicators. One is at the bottom and the other is overlayed on top of the candlestick data. (See screenshot)
First: In the lower chart I do not want to draw values before they are calculated. In this case 14 periods for a Simple Moving Average. (See screenshot with yellow box. Do not want to draw these values)
Second: On the overlay I want the "Open", lowest value, highest value, and "Close" of the last bar. I want to draw a line between these four points and ignore all data in-between. (It should look like the yellow line in the screenshot).
How can i reformat the set chart function to ignore values before 14 periods on the lower line chart?
How can I ignore other points and interpolate between the four values on the line chart for the combined view?
Currently I have to set the values I want "ignored" to zero (1950 in screenshot to make it readable and not squashed) to get around out of bounds errors.
Tried to simplify the code as much as possible to make it more readable here:
//
// ViewController.swift
//
import Foundation
import Cocoa
import Charts
var yValuesIndicatorLower: [Double] = []
var yValuesIndicatorOverlay: [Double] = []
class ViewController: NSViewController {
//Chart view outlets
@IBOutlet weak var combinedChartView: CombinedChartView!
@IBOutlet weak var lineChartView: LineChartView!
// Zoom Buttons
@IBAction func zoomAll(sender: AnyObject) {
combinedChartView.fitScreen()
lineChartView.fitScreen()
}
@IBAction func zoomIn(sender: AnyObject) {
combinedChartView.zoomIn()
lineChartView.zoomIn()
}
@IBAction func zoomOut(sender: AnyObject) {
combinedChartView.zoomOut()
lineChartView.zoomOut()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.wantsLayer = true
view.layer?.backgroundColor = NSColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 0.95).CGColor
combinedChartView.noDataText = "Loading data..."
lineChartView.noDataText = "Loading data..."
// Do any additional setup after loading the view.
let xValues = ["05-16", "05-17", "05-18", "05-19", "05-20", "05-23", "05-24", "05-25", "05-26", "05-27", "05-31", "06-01", "06-02", "06-03", "06-06", "06-07", "06-08", "06-09", "06-10", "06-13", "06-14", "06-15", "06-16", "06-17", "06-20", "06-21", "06-22", "06-23", "06-24", "06-27", "06-28", "06-29", "06-30", "07-01", "07-05", "07-06", "07-07", "07-08", "07-11", "07-12", "07-13", "07-14", "07-15", "07-18", "07-19", "07-20", "07-21", "07-22", "07-25", "07-26", "07-27", "07-28", "07-29", "08-01", "08-02", "08-03"]
////Prices are ["Open"=[0], "High"=[1], "Low"=[2], "Last"[3]]
let yValues: [[Double]] = [[2032.75, 2060.0, 2027.0, 2053.5], [2052.5, 2061.0, 2028.75, 2036.5], [2035.75, 2049.5, 2022.75, 2034.75], [2035.75, 2036.25, 2014.0, 2030.5], [2030.5, 2047.5, 2029.5, 2042.0], [2043.75, 2047.5, 2035.25, 2036.75], [2037.5, 2069.0, 2032.75, 2067.0], [2066.5, 2084.25, 2065.75, 2080.75], [2080.5, 2083.75, 2074.5, 2083.0], [2082.0, 2090.25, 2080.0, 2090.25], [2091.25, 2095.25, 2078.0, 2086.25], [2085.0, 2090.75, 2075.0, 2088.75], [2088.75, 2096.0, 2078.25, 2095.25], [2094.5, 2097.25, 2074.0, 2088.25], [2088.5, 2103.25, 2085.25, 2099.75], [2099.25, 2108.75, 2098.0, 2101.75], [2101.25, 2110.75, 2098.0, 2108.5], [2108.5, 2109.5, 2097.25, 2104.75], [2104.5, 2104.75, 2079.5, 2087.0], [2081.0, 2089.25, 2066.5, 2067.25], [2067.25, 2072.75, 2054.75, 2064.75], [2064.5, 2079.5, 2059.75, 2062.5], [2062.5, 2071.5, 2040.75, 2069.5], [2068.75, 2074.75, 2053.25, 2059.75], [2071.0, 2092.5, 2070.25, 2082.75], [2079.0, 2086.0, 2074.0, 2079.25], [2079.25, 2091.25, 2075.25, 2077.0], [2083.0, 2113.25, 2083.0, 2113.25], [2115.75, 2119.5, 1999.0, 2018.25], [2013.75, 2022.5, 1981.5, 1982.0], [1982.5, 2029.75, 1982.25, 2028.25], [2028.25, 2074.75, 2022.75, 2074.25], [2072.25, 2091.25, 2056.5, 2086.5], [2086.5, 2100.75, 2081.5, 2096.25], [2099.75, 2104.75, 2072.5, 2084.5], [2084.0, 2094.5, 2065.75, 2093.0], [2092.0, 2102.0, 2081.75, 2092.25], [2092.0, 2125.5, 2087.5, 2120.75], [2120.25, 2136.75, 2120.0, 2130.5], [2130.75, 2149.25, 2128.5, 2146.0], [2145.75, 2152.25, 2139.5, 2145.75], [2145.25, 2168.0, 2142.75, 2157.75], [2156.5, 2164.75, 2143.25, 2146.0], [2154.5, 2163.25, 2152.75, 2160.25], [2160.0, 2160.75, 2151.25, 2159.0], [2159.0, 2169.75, 2155.25, 2168.75], [2168.25, 2170.25, 2153.5, 2159.25], [2159.0, 2169.25, 2156.0, 2167.25], [2167.75, 2172.5, 2155.75, 2163.25], [2162.75, 2168.0, 2153.75, 2166.0], [2166.0, 2169.25, 2152.0, 2163.25], [2162.75, 2168.5, 2153.5, 2166.0], [2165.5, 2171.75, 2157.5, 2171.0], [2174.0, 2177.75, 2159.75, 2165.5], [2166.0, 2171.0, 2141.5, 2153.0], [2152.25, 2158.25, 2145.25, 2156.75]]
//Pass values to indicators and get returned indicator values
yValuesIndicatorOverlay = indicatorOverlay(yValues)
yValuesIndicatorLower = indicatorLower(yValues)
//Pass values to chart setting function
setChart(xValues, valuesCandleChart: yValues, indicatorLowerValues: yValuesIndicatorLower, indicatorOverlayValues: yValuesIndicatorOverlay)
}
func indicatorOverlay(yValues: [[Double]]) -> [Double]{
var highest = Double()
var ZigZag: [Double] = []
for i in 0..<yValues.count {
highest = max(highest, yValues[i][1])
}
var lowest = highest
for i in 0..<yValues.count {
lowest = min(lowest, yValues[i][2])
}
for i in 0..<yValues.count {
if i == 0 {
ZigZag.append(yValues[i][0])
}
else if yValues[i][1] == highest {
ZigZag.append(highest)
}
else if yValues[i][2] == lowest {
ZigZag.append(lowest)
}
else if i == yValues.count-1 {
ZigZag.append(yValues[i][3])
}
else {
ZigZag.append(0)//These values should be ignored and then interpolated between other values.
}
}
print(highest)
print(lowest)
return ZigZag
}
func indicatorLower(yValues: [[Double]]) -> [Double]{
let peroid = 14.0
var sum = 0.0
var SMA: [Double] = []
//Simple Moving Average
for i in 0..<Int(peroid) {
sum += yValues[i][3]
if i < Int(peroid)-1 {
SMA.append(0)//These values are to be ignored
}
}
SMA.append(sum/peroid)
for i in Int(peroid)..<yValues.count {
sum = (sum - yValues[i - Int(peroid)][3]) + yValues[i][3]
SMA.append(sum/peroid)
}
return SMA
}
//Function to set chart values
func setChart(xValues: [String], valuesCandleChart: [[Double]], indicatorLowerValues: [Double], indicatorOverlayValues: [Double]) {
var yValsCandleChart : [CandleChartDataEntry] = []
for i in 0..<valuesCandleChart.count {
let high = valuesCandleChart[i][1]
let low = valuesCandleChart[i][2]
let open = valuesCandleChart[i][0]
let close = valuesCandleChart[i][3]
yValsCandleChart.append(CandleChartDataEntry(xIndex: i, shadowH: high, shadowL: low, open: open, close: close))
}
//How to ignore values that are "0" or below a set index?
var indicatorLower_yValues: [ChartDataEntry] = []
for i in 0..<xValues.count {
let indicatorLower_yValue = ChartDataEntry(value: indicatorLowerValues[i], xIndex: i)
indicatorLower_yValues.append(indicatorLower_yValue)
}
//How to use only vlaues that are calculated and not "0" to draw a ZigZag across the candlestick chart?
var indicatorOverlay_yValues: [ChartDataEntry] = []
for i in 0..<xValues.count {
let indicatorOverlay_yValue = ChartDataEntry(value: indicatorOverlayValues[i], xIndex: i)
indicatorOverlay_yValues.append(indicatorOverlay_yValue)
}
let candleChartDataSet = CandleChartDataSet(yVals: yValsCandleChart, label: "Price")
let lineOverlayChartDataSet = LineChartDataSet(yVals: indicatorOverlay_yValues, label: "indicatorOverlay")
let data: CombinedChartData = CombinedChartData(xVals: xValues)
data.candleData = CandleChartData(xVals: xValues, dataSets: [candleChartDataSet])
data.lineData = LineChartData(xVals: xValues, dataSets: [lineOverlayChartDataSet])
combinedChartView.drawOrder = [3, 2]
combinedChartView.data = data
candleChartDataSet.decreasingColor = NSColor.redColor()
candleChartDataSet.increasingColor = NSColor.greenColor()
candleChartDataSet.neutralColor = NSColor.blueColor()
candleChartDataSet.shadowColorSameAsCandle = true
candleChartDataSet.shadowWidth = 1
candleChartDataSet.decreasingFilled = true
candleChartDataSet.increasingFilled = false
candleChartDataSet.drawValuesEnabled = false
combinedChartView.doubleTapToZoomEnabled = false
lineOverlayChartDataSet.drawCirclesEnabled = false
lineOverlayChartDataSet.drawValuesEnabled = false
let lineChartDataSet = LineChartDataSet(yVals: indicatorLower_yValues, label: "indicatorLower")
let lineChartData = LineChartData(xVals: xValues, dataSet: lineChartDataSet)
lineChartView.data = lineChartData
lineChartView.doubleTapToZoomEnabled = false
lineChartDataSet.drawCirclesEnabled = false
lineChartDataSet.drawValuesEnabled = false
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}