Pre loader

Android Multi Pane Stock Charts

Android Chart - Examples

SciChart Android ships with ~90 Android Chart Examples which you can browse, play with, view the source-code and even export each SciChart Android Chart Example to a stand-alone Android Studio project. All of this is possible with the new and improved SciChart Android Examples Suite, which ships as part of our Android Charts SDK.

Download Scichart Android

The Multi-Pane Stock Charts example demonstrates creating a static multi-panel stock chart with Volume and Indicator panes. All charts are synchronized by setting the same VisibleRange for their XAxes. The sizes of all X Axes are synchronized using the SciChartVerticalGroup helper class.

Example Usage

– The main(Price) chart can be scrolled dragging its X Axis. All the other charts are synchronized with it, so they will be scrolled too.
– Zoom to the data extents, double-tapping on any chart. The others will be zoomed to the data extents as well.
– Hover to see XY cursor values from all the charts

The full source code for the Android Multi Pane Stock Charts example is included below (Scroll down!).

Did you know you can also view the source code from one of the following sources as well?

  1. Clone the SciChart.Android.Examples from Github.
  2. Or, view source and export each example to an Android Studio project from the Java version of the SciChart Android Examples app.
  3. Also the SciChart Android Trial contains the full source for the examples (link below).

DOWNLOAD THE ANDROID CHART EXAMPLES

Kotlin: CreateMultiPaneStockChartsFragment.kt
View source code
//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2021. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales:   sales@scichart.com
//
// CreateMultiPaneStockChartsFragment.kt is part of SCICHART®, High Performance Scientific Charts
// For full terms and conditions of the license, see http://www.scichart.com/scichart-eula/
//
// This source code is protected by international copyright law. Unauthorized
// reproduction, reverse-engineering, or distribution of all or any portion of
// this source code is strictly prohibited.
//
// This source code contains confidential and proprietary trade secrets of
// SciChart Ltd., and should at no time be copied, transferred, sold,
// distributed or made available without express written permission.
//******************************************************************************

package com.scichart.examples.fragments.examples2d.createStockCharts.kt

import android.view.LayoutInflater
import android.view.View
import com.scichart.charting.Direction2D.XDirection
import com.scichart.charting.model.dataSeries.XyDataSeries
import com.scichart.charting.modifiers.AxisDragModifierBase.AxisDragMode.Pan
import com.scichart.charting.visuals.SciChartSurface
import com.scichart.charting.visuals.axes.AutoRange
import com.scichart.charting.visuals.axes.NumericAxis
import com.scichart.charting.visuals.renderableSeries.FastColumnRenderableSeries
import com.scichart.charting.visuals.renderableSeries.data.XSeriesRenderPassData
import com.scichart.charting.visuals.renderableSeries.paletteProviders.IFillPaletteProvider
import com.scichart.charting.visuals.renderableSeries.paletteProviders.IStrokePaletteProvider
import com.scichart.charting.visuals.renderableSeries.paletteProviders.PaletteProviderBase
import com.scichart.charting.visuals.synchronization.SciChartVerticalGroup
import com.scichart.core.model.IntegerValues
import com.scichart.data.model.DoubleRange
import com.scichart.examples.R
import com.scichart.examples.data.DataManager
import com.scichart.examples.data.MovingAverage
import com.scichart.examples.data.PriceSeries
import com.scichart.examples.databinding.ExampleMultipaneStockChartsFragmentBinding
import com.scichart.examples.fragments.base.ExampleBaseFragment
import com.scichart.examples.utils.scichartExtensions.SolidBrushStyle
import com.scichart.examples.utils.scichartExtensions.SolidPenStyle
import com.scichart.examples.utils.scichartExtensions.annotations
import com.scichart.examples.utils.scichartExtensions.axis
import com.scichart.examples.utils.scichartExtensions.axisMarkerAnnotation
import com.scichart.examples.utils.scichartExtensions.categoryDateAxis
import com.scichart.examples.utils.scichartExtensions.chartModifiers
import com.scichart.examples.utils.scichartExtensions.drawable
import com.scichart.examples.utils.scichartExtensions.fastBandRenderableSeries
import com.scichart.examples.utils.scichartExtensions.fastCandlestickRenderableSeries
import com.scichart.examples.utils.scichartExtensions.fastColumnRenderableSeries
import com.scichart.examples.utils.scichartExtensions.fastLineRenderableSeries
import com.scichart.examples.utils.scichartExtensions.legendModifier
import com.scichart.examples.utils.scichartExtensions.modifierGroup
import com.scichart.examples.utils.scichartExtensions.ohlcDataSeries
import com.scichart.examples.utils.scichartExtensions.pinchZoomModifier
import com.scichart.examples.utils.scichartExtensions.renderableSeries
import com.scichart.examples.utils.scichartExtensions.suspendUpdates
import com.scichart.examples.utils.scichartExtensions.xAxes
import com.scichart.examples.utils.scichartExtensions.xAxisDragModifier
import com.scichart.examples.utils.scichartExtensions.xyDataSeries
import com.scichart.examples.utils.scichartExtensions.xyyDataSeries
import com.scichart.examples.utils.scichartExtensions.yAxes
import com.scichart.examples.utils.scichartExtensions.zoomExtentsModifier
import com.scichart.examples.utils.scichartExtensions.zoomPanModifier
import java.util.Date

class CreateMultiPaneStockChartsFragment : ExampleBaseFragment<ExampleMultipaneStockChartsFragmentBinding>() {
    private val verticalGroup = SciChartVerticalGroup()
    private val sharedXRange = DoubleRange()

    override fun showDefaultModifiersInToolbar(): Boolean = false

    override fun inflateBinding(inflater: LayoutInflater): ExampleMultipaneStockChartsFragmentBinding {
        return ExampleMultipaneStockChartsFragmentBinding.inflate(inflater)
    }

    override fun initExample(binding: ExampleMultipaneStockChartsFragmentBinding) {
        binding.macdChart.theme = R.style.SciChart_NavyBlue
        binding.priceChart.theme = R.style.SciChart_NavyBlue
        binding.rsiChart.theme = R.style.SciChart_NavyBlue
        binding.volumeChart.theme = R.style.SciChart_NavyBlue

        val priceData = DataManager.getInstance().getPriceDataEurUsd(activity)

        initPriceChart(binding.priceChart, priceData)
        initMacdChart(binding.macdChart, priceData)
        initRsiChart(binding.rsiChart, priceData)
        initVolumeChart(binding.volumeChart, priceData)
    }

    private fun initPriceChart(surface: SciChartSurface, prices: PriceSeries) {
        surface.suspendUpdates {
            initChart(this, true)

            val maLow = MovingAverage.movingAverage(prices.closeData, 50)
            val maHigh = MovingAverage.movingAverage(prices.closeData, 200)

            yAxes {
                axis(createNumericAxis(PRICES, "$0.0000", true))
            }
            renderableSeries {
                fastCandlestickRenderableSeries {
                    ohlcDataSeries<Date, Double>("EUR/USD") {
                        append(prices.dateData, prices.openData, prices.highData, prices.lowData, prices.closeData)
                    }
                    yAxisId = PRICES

                    strokeUpStyle = SolidPenStyle(0xFF67BDAF)
                    fillUpBrushStyle = SolidBrushStyle(0xFF447487)

                    strokeDownStyle = SolidPenStyle(0xFFDC7969)
                    fillDownBrushStyle = SolidBrushStyle(0x77DC7969)
                }
                fastLineRenderableSeries {
                    xyDataSeries<Date, Double>("Low Line") {
                        append(prices.dateData, maLow)
                    }
                    yAxisId = PRICES
                    strokeStyle = SolidPenStyle(0xFFEC0F6C)
                }
                fastLineRenderableSeries {
                    xyDataSeries<Date, Double>("High Line") {
                        append(prices.dateData, maHigh)
                    }
                    yAxisId = PRICES
                    strokeStyle = SolidPenStyle(0xFF50C7E0)
                }
            }

            annotations {
                axisMarkerAnnotation { y1 = prices.closeData.last(); yAxisId = PRICES; background = 0xFF67BDAF.drawable() }
                axisMarkerAnnotation { y1 = maLow.last(); yAxisId = PRICES; background = 0xFFEC0F6C.drawable() }
                axisMarkerAnnotation { y1 = maHigh.last(); yAxisId = PRICES; background = 0xFF50C7E0.drawable() }
            }
        }
    }

    private fun initVolumeChart(surface: SciChartSurface, prices: PriceSeries) {
        surface.suspendUpdates {
            initChart(surface, false)

            yAxes {
                axis(createNumericAxis(VOLUME, "###E+0", false))
            }
            renderableSeries {
                fastColumnRenderableSeries {
                    xyDataSeries<Date, Double>(VOLUME) {
                        append(prices.dateData, prices.volumeData.map(Long::toDouble))
                    }
                    yAxisId = VOLUME
                    paletteProvider = VolumePaletteProvider(prices)
                }
            }
            annotations {
                axisMarkerAnnotation { y1 = prices.volumeData.last().toDouble(); yAxisId = VOLUME }
            }
        }
    }

    private fun initRsiChart(surface: SciChartSurface, prices: PriceSeries) {
        surface.suspendUpdates {
            initChart(surface, false)
            val rsi = MovingAverage.rsi(prices, 14)

            yAxes {
                axis(createNumericAxis(RSI, "0.0", false))
            }
            renderableSeries {
                fastLineRenderableSeries {
                    xyDataSeries<Date, Double>(RSI) {
                        append(prices.dateData, rsi)
                    }
                    yAxisId = RSI
                    strokeStyle = SolidPenStyle(0xFF537ABD)
                }
            }
            annotations {
                axisMarkerAnnotation { y1 = rsi.last(); yAxisId = RSI }
            }
        }
    }

    private fun initMacdChart(surface: SciChartSurface, prices: PriceSeries) {
        surface.suspendUpdates {
            initChart(surface, false)
            val macd = MovingAverage.macd(prices.closeData, 12, 25, 9)

            yAxes {
                axis(createNumericAxis(MACD, "0.00", false))
            }
            renderableSeries {
                fastColumnRenderableSeries {
                    xyDataSeries<Date, Double>("Histogram") {
                        append(prices.dateData, macd.divergenceValues)
                    }
                    yAxisId = MACD
                    paletteProvider = MacdHistogramPaletteProvider()
                }
                fastBandRenderableSeries {
                    xyyDataSeries<Date, Double>(MACD) {
                        append(prices.dateData, macd.macdValues, macd.signalValues)
                    }
                    yAxisId = MACD

                    strokeStyle = SolidPenStyle(0xFF67BDAF)
                    strokeY1Style = SolidPenStyle(0xFFDC7969)

                    fillBrushStyle = SolidBrushStyle(0x77DC7969)
                    fillY1BrushStyle = SolidBrushStyle(0x7767BDAF)
                }
            }
            annotations {
                axisMarkerAnnotation { y1 = macd.divergenceValues.last(); yAxisId = MACD }
                axisMarkerAnnotation { y1 = macd.macdValues.last(); yAxisId = MACD }
            }
        }
    }

    private fun initChart(surface: SciChartSurface, isMainPane: Boolean) {
        surface.run {
            xAxes {
                categoryDateAxis {
                    visibility = if (isMainPane) View.VISIBLE else View.GONE
                    visibleRange = sharedXRange
                    growBy = DoubleRange(0.0, 0.05)
                }
            }

            chartModifiers { modifierGroup(context) {
                xAxisDragModifier { receiveHandledEvents = true; dragMode = Pan }
                pinchZoomModifier { receiveHandledEvents = true; direction = XDirection }
                zoomPanModifier { receiveHandledEvents = true }
                zoomExtentsModifier { receiveHandledEvents = true }
                legendModifier { setShowCheckboxes(false) }
            }}
        }

        verticalGroup.addSurfaceToGroup(surface)
    }

    fun createNumericAxis(title: String, yAxisTextFormatting: String, isMainPane: Boolean): NumericAxis {
        return NumericAxis(context).apply {
            axisId = title
            textFormatting = yAxisTextFormatting
            autoRange = AutoRange.Always
            minorsPerMajor = if (isMainPane) 4 else 2
            maxAutoTicks = if (isMainPane) 8 else 4
            growBy = if (isMainPane) DoubleRange(0.05, 0.05) else DoubleRange(0.0, 0.0)
        }
    }


    internal class VolumePaletteProvider constructor(private val prices: PriceSeries) :
        PaletteProviderBase<FastColumnRenderableSeries>(FastColumnRenderableSeries::class.java),
        IFillPaletteProvider, IStrokePaletteProvider {
        private val colors = IntegerValues()
        private val desiredColors = intArrayOf(-0x984251, -0x238697)
        override fun update() {
            val currentRenderPassData =
                renderableSeries!!.currentRenderPassData as XSeriesRenderPassData
            val size = currentRenderPassData.pointsCount()
            colors.setSize(size)
            val colorsArray = colors.itemsArray
            val indices = currentRenderPassData.xValues.itemsArray

            for (i in 0 until size) {
                val index = indices[i]
                val open = prices[index.toInt()].open
                val close = prices[index.toInt()].close

                if (close - open > 0) {
                    colorsArray[i] = desiredColors[0]
                } else {
                    colorsArray[i] = desiredColors[1]
                }
            }
        }

        override fun getFillColors(): IntegerValues {
            return colors
        }

        override fun getStrokeColors(): IntegerValues {
            return colors
        }
    }


    internal class MacdHistogramPaletteProvider:
        PaletteProviderBase<FastColumnRenderableSeries>(FastColumnRenderableSeries::class.java),
        IFillPaletteProvider, IStrokePaletteProvider {
        private val colors = IntegerValues()
        private val desiredColors = intArrayOf(-0x984251, -0x238697)
        override fun update() {
            val currentRenderPassData =
                renderableSeries!!.currentRenderPassData as XSeriesRenderPassData
            val size = currentRenderPassData.pointsCount()
            colors.setSize(size)
            val colorsArray = colors.itemsArray
            val indices = currentRenderPassData.xValues.itemsArray
            val dataSeries = renderableSeries!!.dataSeries as XyDataSeries<Date, Double>
            for (i in 0 until size) {
                val index = indices[i]
                val value = dataSeries.yValues[index.toInt()]
                if (value > 0) {
                    colorsArray[i] = desiredColors[0]
                } else {
                    colorsArray[i] = desiredColors[1]
                }
            }
        }

        override fun getFillColors(): IntegerValues {
            return colors
        }

        override fun getStrokeColors(): IntegerValues {
            return colors
        }
    }


    companion object {
        private const val VOLUME = "Volume"
        private const val PRICES = "Prices"
        private const val RSI = "RSI"
        private const val MACD = "MACD"
    }
}
Java: CreateMultiPaneStockChartsFragment.java
View source code
//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2021. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales:   sales@scichart.com
//
// CreateMultiPaneStockChartsFragment.java is part of SCICHART®, High Performance Scientific Charts
// For full terms and conditions of the license, see http://www.scichart.com/scichart-eula/
//
// This source code is protected by international copyright law. Unauthorized
// reproduction, reverse-engineering, or distribution of all or any portion of
// this source code is strictly prohibited.
//
// This source code contains confidential and proprietary trade secrets of
// SciChart Ltd., and should at no time be copied, transferred, sold,
// distributed or made available without express written permission.
//******************************************************************************

package com.scichart.examples.fragments.examples2d.createStockCharts;

import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;

import androidx.annotation.NonNull;

import com.scichart.charting.ClipMode;
import com.scichart.charting.Direction2D;
import com.scichart.charting.model.AnnotationCollection;
import com.scichart.charting.model.RenderableSeriesCollection;
import com.scichart.charting.model.dataSeries.OhlcDataSeries;
import com.scichart.charting.model.dataSeries.XyDataSeries;
import com.scichart.charting.model.dataSeries.XyyDataSeries;
import com.scichart.charting.modifiers.AxisDragModifierBase;
import com.scichart.charting.visuals.SciChartSurface;
import com.scichart.charting.visuals.axes.AutoRange;
import com.scichart.charting.visuals.axes.CategoryDateAxis;
import com.scichart.charting.visuals.axes.NumericAxis;
import com.scichart.charting.visuals.renderableSeries.BaseRenderableSeries;
import com.scichart.charting.visuals.renderableSeries.FastColumnRenderableSeries;
import com.scichart.charting.visuals.renderableSeries.data.XSeriesRenderPassData;
import com.scichart.charting.visuals.renderableSeries.paletteProviders.IFillPaletteProvider;
import com.scichart.charting.visuals.renderableSeries.paletteProviders.IStrokePaletteProvider;
import com.scichart.charting.visuals.renderableSeries.paletteProviders.PaletteProviderBase;
import com.scichart.charting.visuals.synchronization.SciChartVerticalGroup;
import com.scichart.core.model.IntegerValues;
import com.scichart.core.utility.ListUtil;
import com.scichart.data.model.DoubleRange;
import com.scichart.examples.R;
import com.scichart.examples.data.DataManager;
import com.scichart.examples.data.MovingAverage;
import com.scichart.examples.data.PriceSeries;
import com.scichart.examples.databinding.ExampleMultipaneStockChartsFragmentBinding;
import com.scichart.examples.fragments.base.ExampleBaseFragment;
import com.scichart.extensions.builders.SciChartBuilder;

import java.util.Collections;
import java.util.Date;

public class CreateMultiPaneStockChartsFragment extends ExampleBaseFragment<ExampleMultipaneStockChartsFragmentBinding> {
    private static final String VOLUME = "Volume";
    private static final String PRICES = "Prices";
    private static final String RSI = "RSI";
    private static final String MACD = "MACD";

    private final SciChartVerticalGroup verticalGroup = new SciChartVerticalGroup();
    private final DoubleRange sharedXRange = new DoubleRange();

    @Override
    public boolean showDefaultModifiersInToolbar() {
        return false;
    }

    @NonNull
    @Override
    protected ExampleMultipaneStockChartsFragmentBinding inflateBinding(@NonNull LayoutInflater inflater) {
        return ExampleMultipaneStockChartsFragmentBinding.inflate(inflater);
    }

    @Override
    protected void initExample(ExampleMultipaneStockChartsFragmentBinding binding) {
        binding.macdChart.setTheme(R.style.SciChart_NavyBlue);
        binding.priceChart.setTheme(R.style.SciChart_NavyBlue);
        binding.rsiChart.setTheme(R.style.SciChart_NavyBlue);
        binding.volumeChart.setTheme(R.style.SciChart_NavyBlue);

        final PriceSeries priceData = DataManager.getInstance().getPriceDataEurUsd(getActivity());

        final PricePaneModel pricePaneModel = new PricePaneModel(sciChartBuilder, priceData);
        final MacdPaneModel macdPaneModel = new MacdPaneModel(sciChartBuilder, priceData);
        final RsiPaneModel rsiPaneModel = new RsiPaneModel(sciChartBuilder, priceData);
        final VolumePaneModel volumePaneModel = new VolumePaneModel(sciChartBuilder, priceData);

        initChart(binding.priceChart, pricePaneModel, true);
        initChart(binding.macdChart, macdPaneModel, false);
        initChart(binding.rsiChart, rsiPaneModel, false);
        initChart(binding.volumeChart, volumePaneModel, false);
    }

    private void initChart(SciChartSurface surface, BasePaneModel model, boolean isMainPane) {
        final CategoryDateAxis xAxis = sciChartBuilder.newCategoryDateAxis()
                .withVisibility(isMainPane ? View.VISIBLE : View.GONE)
                .withVisibleRange(sharedXRange)
                .withGrowBy(0, 0.05)
                .build();

        surface.getXAxes().add(xAxis);
        surface.getYAxes().add(model.yAxis);

        surface.getRenderableSeries().addAll(model.renderableSeries);

        surface.getChartModifiers().add(sciChartBuilder
                .newModifierGroup()
                    .withXAxisDragModifier().withReceiveHandledEvents(true).withDragMode(AxisDragModifierBase.AxisDragMode.Pan).withClipModeX(ClipMode.StretchAtExtents).build()
                    .withPinchZoomModifier().withReceiveHandledEvents(true).withXyDirection(Direction2D.XDirection).build()
                    .withZoomPanModifier().withReceiveHandledEvents(true).build()
                    .withZoomExtentsModifier().withReceiveHandledEvents(true).build()
                    .withLegendModifier().withShowCheckBoxes(false).build()
                .build());

        surface.setAnnotations(model.annotations);

        verticalGroup.addSurfaceToGroup(surface);
    }

    private abstract static class BasePaneModel {
        public final RenderableSeriesCollection renderableSeries = new RenderableSeriesCollection();
        public final AnnotationCollection annotations = new AnnotationCollection();
        public final NumericAxis yAxis;
        public final String title;

        protected BasePaneModel(SciChartBuilder builder, String title, String yAxisTextFormatting, boolean isMainPane) {
            this.title = title;

            this.yAxis = builder.newNumericAxis()
                    .withAxisId(title)
                    .withTextFormatting(yAxisTextFormatting)
                    .withAutoRangeMode(AutoRange.Always)
                    .withMinorsPerMajor(isMainPane ? 4 : 2)
                    .withMaxAutoTicks(isMainPane ? 8 : 4)
                    .withGrowBy(isMainPane ? new DoubleRange(0.05d, 0.05d) : new DoubleRange(0d, 0d))
                    .build();
        }

        final void addRenderableSeries(BaseRenderableSeries renderableSeries) {
            renderableSeries.setClipToBounds(true);
            this.renderableSeries.add(renderableSeries);
        }
    }

    private static class PricePaneModel extends BasePaneModel {

        public PricePaneModel(SciChartBuilder builder, PriceSeries prices) {
            super(builder, PRICES, "$0.0000", true);

            // Add the main OHLC chart
            final OhlcDataSeries<Date, Double> stockPrices = builder.newOhlcDataSeries(Date.class, Double.class).withSeriesName("EUR/USD").build();
            stockPrices.append(prices.getDateData(), prices.getOpenData(), prices.getHighData(), prices.getLowData(), prices.getCloseData());
            addRenderableSeries(builder
                    .newCandlestickSeries()
                    .withDataSeries(stockPrices)
                    .withYAxisId(PRICES)
                    .withStrokeUp(0xFF67BDAF).withFillUpColor(0xFF447487)
                    .withStrokeDown(0xFFDC7969).withFillDownColor(0x77DC7969)
                    .build()
            );

            final XyDataSeries<Date, Double> maLow = builder.newXyDataSeries(Date.class, Double.class).withSeriesName("Low Line").build();
            maLow.append(prices.getDateData(), MovingAverage.movingAverage(prices.getCloseData(), 50));
            addRenderableSeries(builder.newLineSeries().withDataSeries(maLow).withStrokeStyle(0xFFEC0F6C, 1f).withYAxisId(PRICES).build());

            final XyDataSeries<Date, Double> maHigh = builder.newXyDataSeries(Date.class, Double.class).withSeriesName("High Line").build();
            maHigh.append(prices.getDateData(), MovingAverage.movingAverage(prices.getCloseData(), 200));
            addRenderableSeries(builder.newLineSeries().withDataSeries(maHigh).withStrokeStyle(0xFF50C7E0, 1f).withYAxisId(PRICES).build());

            Collections.addAll(annotations,
                    builder.newAxisMarkerAnnotation().withY1(stockPrices.getYValues().get(stockPrices.getCount() - 1)).withBackgroundColor(0xFF67BDAF).withYAxisId(PRICES).build(),
                    builder.newAxisMarkerAnnotation().withY1(maLow.getYValues().get(maLow.getCount() - 1)).withBackgroundColor(0xFFEC0F6C).withYAxisId(PRICES).build(),
                    builder.newAxisMarkerAnnotation().withY1(maHigh.getYValues().get(maHigh.getCount() - 1)).withBackgroundColor(0xFF50C7E0).withYAxisId(PRICES).build());
        }
    }

    private static class VolumePaneModel extends BasePaneModel {
        public VolumePaneModel(SciChartBuilder builder, PriceSeries prices) {
            super(builder, VOLUME, "###E+0", false);

            final XyDataSeries<Date, Double> volumePrices = builder.newXyDataSeries(Date.class, Double.class).withSeriesName(VOLUME).build();
            volumePrices.append(prices.getDateData(), ListUtil.select(prices.getVolumeData(), Long::doubleValue));
            addRenderableSeries(builder
                    .newColumnSeries()
                    .withDataSeries(volumePrices)
                    .withYAxisId(VOLUME)
                    .withPaletteProvider(new VolumePaletteProvider(prices))
                    .build()
            );

            Collections.addAll(annotations,
                    builder.newAxisMarkerAnnotation().withY1(volumePrices.getYValues().get(volumePrices.getCount() - 1)).withYAxisId(VOLUME).build());
        }

        class VolumePaletteProvider extends PaletteProviderBase<FastColumnRenderableSeries> implements IFillPaletteProvider, IStrokePaletteProvider {
            private final IntegerValues colors = new IntegerValues();
            private final int[] desiredColors = new int[]{0xFF67BDAF, 0xFFDC7969};

            private PriceSeries prices;

            protected VolumePaletteProvider(PriceSeries prices) {
                super(FastColumnRenderableSeries.class);
                this.prices = prices;
            }

            @Override
            public void update() {
                final XSeriesRenderPassData currentRenderPassData = (XSeriesRenderPassData) renderableSeries.getCurrentRenderPassData();

                final int size = currentRenderPassData.pointsCount();
                colors.setSize(size);

                final int[] colorsArray = colors.getItemsArray();
                final double[] indices = currentRenderPassData.xValues.getItemsArray();

                for (int i = 0; i < size; i++) {
                    final double index = indices[i];
                    double open = prices.get((int) index).getOpen();
                    double close = prices.get((int) index).getClose();
                    if(close - open > 0 ){
                        colorsArray[i] = desiredColors[0];
                    } else {
                        colorsArray[i] = desiredColors[1];
                    }
                }
            }

            @Override
            public IntegerValues getFillColors() {
                return colors;
            }

            @Override
            public IntegerValues getStrokeColors() {
                return colors;
            }
        }
    }

    private static class RsiPaneModel extends BasePaneModel {
        public RsiPaneModel(SciChartBuilder builder, PriceSeries prices) {
            super(builder, RSI, "0.0", false);

            final XyDataSeries<Date, Double> rsiSeries = builder.newXyDataSeries(Date.class, Double.class).withSeriesName(RSI).build();
            rsiSeries.append(prices.getDateData(), MovingAverage.rsi(prices, 14));
            addRenderableSeries(builder.newLineSeries().withDataSeries(rsiSeries).withStrokeStyle(0xFF537ABD, 1f).withYAxisId(RSI).build());

            Collections.addAll(annotations,
                    builder.newAxisMarkerAnnotation().withY1(rsiSeries.getYValues().get(rsiSeries.getCount() - 1)).withYAxisId(RSI).build());
        }
    }

    private static class MacdPaneModel extends BasePaneModel {
        public MacdPaneModel(SciChartBuilder builder, PriceSeries prices) {
            super(builder, MACD, "0.00", false);

            final MovingAverage.MacdPoints macdPoints = MovingAverage.macd(prices.getCloseData(), 12, 25, 9);

            final XyDataSeries<Date, Double> histogramDataSeries = builder.newXyDataSeries(Date.class, Double.class).withSeriesName("Histogram").build();
            histogramDataSeries.append(prices.getDateData(), macdPoints.divergenceValues);
            addRenderableSeries(builder
                    .newColumnSeries()
                    .withDataSeries(histogramDataSeries)
                    .withPaletteProvider(new MacdHistogramPaletteProvider())
                    .withYAxisId(MACD)
                    .build()
            );

            final XyyDataSeries<Date, Double> macdDataSeries = builder.newXyyDataSeries(Date.class, Double.class).withSeriesName(MACD).build();
            macdDataSeries.append(prices.getDateData(), macdPoints.macdValues, macdPoints.signalValues);
            addRenderableSeries(builder
                    .newBandSeries()
                    .withDataSeries(macdDataSeries)
                    .withYAxisId(MACD)
                    .withStrokeStyle(0xFF67BDAF).withStrokeY1Style(0xFFDC7969)
                    .withFillColor(0x77DC7969).withFillY1Color(0x7767BDAF)
                    .build()
            );

            Collections.addAll(annotations,
                    builder.newAxisMarkerAnnotation().withY1(histogramDataSeries.getYValues().get(histogramDataSeries.getCount() - 1)).withYAxisId(MACD).build(),
                    builder.newAxisMarkerAnnotation().withY1(macdDataSeries.getYValues().get(macdDataSeries.getCount() - 1)).withYAxisId(MACD).build());
        }

        class MacdHistogramPaletteProvider extends PaletteProviderBase<FastColumnRenderableSeries> implements IFillPaletteProvider, IStrokePaletteProvider {
            private final IntegerValues colors = new IntegerValues();
            private final int[] desiredColors = new int[]{0xFF67BDAF, 0xFFDC7969};

            protected MacdHistogramPaletteProvider() {
                super(FastColumnRenderableSeries.class);
            }

            @Override
            public void update() {
                final XSeriesRenderPassData currentRenderPassData = (XSeriesRenderPassData) renderableSeries.getCurrentRenderPassData();

                final int size = currentRenderPassData.pointsCount();
                colors.setSize(size);

                final int[] colorsArray = colors.getItemsArray();
                final double[] indices = currentRenderPassData.xValues.getItemsArray();

                XyDataSeries<Date, Double> dataSeries = (XyDataSeries<Date, Double>) renderableSeries.getDataSeries();

                for (int i = 0; i < size; i++) {
                    final double index = indices[i];
                    double value = dataSeries.getYValues().get((int) index);
                    if(value > 0 ){
                        colorsArray[i] = desiredColors[0];
                    } else {
                        colorsArray[i] = desiredColors[1];
                    }
                }
            }

            @Override
            public IntegerValues getFillColors() {
                return colors;
            }

            @Override
            public IntegerValues getStrokeColors() {
                return colors;
            }
        }
    }
}
Back to Android Chart Examples