Skip to content

Commit

Permalink
增加RSI指标
Browse files Browse the repository at this point in the history
  • Loading branch information
wangyiqian committed Mar 9, 2023
1 parent 4c504f4 commit d10cb97
Show file tree
Hide file tree
Showing 8 changed files with 586 additions and 10 deletions.
18 changes: 14 additions & 4 deletions lib/src/main/java/com/github/wangyiqian/stockchart/Default.kt
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,21 @@ object DefaultIndexParams {
const val BOLL = "20,2"
const val MACD = "12,26,9"
const val KDJ = "9,3,3"
const val RSI = "6,12,24"
}

object DefaultIndexTextFormatter {
val MA: (idx: Int, value: Float?) -> String = { idx, value ->
"MA${DefaultIndexParams.MA.split(",")
.map { it.trim() }[idx]}:${value?.let { NumberFormatUtil.formatPrice(it) } ?: "——"}"
"MA${
DefaultIndexParams.MA.split(",")
.map { it.trim() }[idx]
}:${value?.let { NumberFormatUtil.formatPrice(it) } ?: "——"}"
}
val EMA: (idx: Int, value: Float?) -> String = { idx, value ->
"EMA${DefaultIndexParams.EMA.split(",")
.map { it.trim() }[idx]}:${value?.let { NumberFormatUtil.formatPrice(it) } ?: "——"}"
"EMA${
DefaultIndexParams.EMA.split(",")
.map { it.trim() }[idx]
}:${value?.let { NumberFormatUtil.formatPrice(it) } ?: "——"}"
}
val BOLL: (idx: Int, value: Float?) -> String = { idx, value ->
val prefix = when (idx) {
Expand Down Expand Up @@ -173,6 +178,11 @@ object DefaultIndexTextFormatter {
}
"$prefix${value?.let { NumberFormatUtil.formatPrice(it) } ?: "——"}"
}
val RSI: (idx: Int, value: Float?) -> String = { idx, value ->
"RSI${
DefaultIndexParams.RSI.split(",").map { it.trim() }[idx]
}:${value?.let { NumberFormatUtil.formatPrice(it) } ?: "——"}"
}
}

object DefaultIndexStartText {
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.github.wangyiqian.stockchart.childchart.rskchart

import android.graphics.Bitmap
import android.graphics.Color
import android.view.View
import com.github.wangyiqian.stockchart.*
import com.github.wangyiqian.stockchart.childchart.base.BaseChildChartConfig
import com.github.wangyiqian.stockchart.childchart.base.HighlightLabelConfig
import com.github.wangyiqian.stockchart.index.Index
import com.github.wangyiqian.stockchart.listener.OnHighlightListener

/**
* @author wangyiqian E-mail: wangyiqian9891@gmail.com
* @version 创建时间: 2023/3/9
*/
class RsiChartConfig(
height: Int = DEFAULT_CHILD_CHART_HEIGHT,
marginTop: Int = DEFAULT_CHILD_CHART_MARGIN_TOP,
marginBottom: Int = DEFAULT_CHILD_CHART_MARGIN_BOTTOM,
onHighlightListener: OnHighlightListener? = null,
chartMainDisplayAreaPaddingTop: Float = DEFAULT_CHART_MAIN_DISPLAY_AREA_PADDING_TOP,
chartMainDisplayAreaPaddingBottom: Float = DEFAULT_CHART_MAIN_DISPLAY_AREA_PADDING_BOTTOM,
// 长按时高亮线左侧标签配置
var highlightLabelLeft: HighlightLabelConfig? = null,
// 长按时高亮线右侧标签配置
var highlightLabelRight: HighlightLabelConfig? = null,
// 指标线的颜色
var indexColors: List<Int> = listOf(
Color.parseColor("#F5EC58"),
Color.parseColor("#FF7CE5"),
Color.parseColor("#9EC7FE"),
Color.parseColor("#fb0606"),
Color.parseColor("#a003fa"),
Color.parseColor("#02cefa"),
Color.parseColor("#02fa88"),
Color.parseColor("#fa6b02")
),
// 指标线宽度
var lineStrokeWidth: Float = 3f,
// 虚线颜色
var dashLineColor: Int = Color.LTGRAY,
// 需要展示的指标配置
var index: Index? = Index.RSI(),
// 指标头文字背景色
var indexStarterBgColor: Int = Color.TRANSPARENT,
// 指标头文字背景水平内间距
var indexStarterBgPaddingHorizontal: Float = 0f,
// 指标头文字右侧图标
var indexStarterRightIcon: Bitmap? = null,
// 指标头文字点击事件
var indexStarterClickListener: ((View) -> Unit)? = null
) : BaseChildChartConfig(
height,
marginTop,
marginBottom,
onHighlightListener,
chartMainDisplayAreaPaddingTop,
chartMainDisplayAreaPaddingBottom
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.github.wangyiqian.stockchart.childchart.rskchart

import com.github.wangyiqian.stockchart.IStockChart
import com.github.wangyiqian.stockchart.childchart.base.AbsChildChartFactory

/**
* @author wangyiqian E-mail: wangyiqian9891@gmail.com
* @version 创建时间: 2023/3/9
*/
class RsiChartFactory(stockChart: IStockChart, childChartConfig: RsiChartConfig) :
AbsChildChartFactory<RsiChartConfig>(stockChart, childChartConfig) {
override fun createChart() = RsiChart(stockChart, childChartConfig)
}
22 changes: 22 additions & 0 deletions lib/src/main/java/com/github/wangyiqian/stockchart/index/Index.kt
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,27 @@ open abstract class Index(
) {
override fun calculate(input: List<IKEntity>) = KDJCalculator.calculate(param, input)
}

class RSI(
param: String = DefaultIndexParams.RSI,
startText: String = "RSI",
startTextColor: Int = DEFAULT_INDEX_START_TEXT_COLOR,
textFormatter: (idx: Int, value: Float?) -> String = DefaultIndexTextFormatter.RSI,
textMarginLeft: Float = DEFAULT_INDEX_TEXT_MARGIN_LEFT,
textMarginTopDp: Float = DEFAULT_INDEX_TEXT_MARGIN_TOP,
textSpace: Float = DEFAULT_INDEX_TEXT_SPACE,
textSize: Float = DEFAULT_INDEX_TEXT_SIZE
) : Index(
param,
startText,
startTextColor,
textFormatter,
textMarginLeft,
textMarginTopDp,
textSpace,
textSize
) {
override fun calculate(input: List<IKEntity>) = RSICalculator.calculate(param, input)
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.github.wangyiqian.stockchart.index

import com.github.wangyiqian.stockchart.entities.FLAG_EMPTY
import com.github.wangyiqian.stockchart.entities.IKEntity
import com.github.wangyiqian.stockchart.entities.containFlag
import kotlin.math.max
import kotlin.math.min

/**
* @author wangyiqian E-mail: wangyiqian9891@gmail.com
* @version 创建时间: 2023/3/9
*/
object RSICalculator : ICalculator {
override fun calculate(param: String, input: List<IKEntity>): List<List<Float?>> {
val paramList = param.split(",")
val periodList = paramList.map { it.toInt() }
val result = MutableList(periodList.size) { MutableList<Float?>(input.size) { 0f } }
val preAvgRiseList = MutableList(periodList.size) { 0f }
val preAvgDownList = MutableList(periodList.size) { 0f }
var preNotEmptyEntityCount = 0
var preKEntity: IKEntity? = null
input.forEachIndexed { kEntityIdx, kEntity ->
if (kEntity.containFlag(FLAG_EMPTY)) {
preNotEmptyEntityCount = 0
preKEntity = null
periodList.forEachIndexed { periodListIdx, _ ->
preAvgRiseList[periodListIdx] = 0f
preAvgDownList[periodListIdx] = 0f
result[periodListIdx][kEntityIdx] = null
}
return@forEachIndexed
}

periodList.forEachIndexed { periodListIdx, period ->
val changeAmount =
if (kEntityIdx == 0) 0f else kEntity.getClosePrice() - (preKEntity?.getClosePrice()
?: 0f)
val n = min(preNotEmptyEntityCount + 1, period)
val preAvgRise = if (kEntityIdx == 0) 0f else preAvgRiseList[periodListIdx]
val preAvgDown = if (kEntityIdx == 0) 0f else preAvgDownList[periodListIdx]
val avgRise =
((if (n == 1) 0f else (preAvgRise * (n - 1))) + max(changeAmount, 0f)) / n
val avgDown =
((if (n == 1) 0f else (preAvgDown * (n - 1))) + max(-changeAmount, 0f)) / n
result[periodListIdx][kEntityIdx] =
if (kEntityIdx == 0 || avgRise + avgDown == 0f) 0f else 100 * avgRise / (avgRise + avgDown)
preAvgRiseList[periodListIdx] = avgRise
preAvgDownList[periodListIdx] = avgDown
}
preKEntity = kEntity
preNotEmptyEntityCount++
}
return result
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import com.github.wangyiqian.stockchart.childchart.kdjchart.KdjChartConfig
import com.github.wangyiqian.stockchart.childchart.kdjchart.KdjChartFactory
import com.github.wangyiqian.stockchart.childchart.macdchart.MacdChartConfig
import com.github.wangyiqian.stockchart.childchart.macdchart.MacdChartFactory
import com.github.wangyiqian.stockchart.childchart.rskchart.RsiChartConfig
import com.github.wangyiqian.stockchart.childchart.rskchart.RsiChartFactory
import com.github.wangyiqian.stockchart.childchart.timebar.TimeBarConfig
import com.github.wangyiqian.stockchart.childchart.timebar.TimeBarFactory
import com.github.wangyiqian.stockchart.childchart.volumechart.VolumeChartConfig
Expand Down Expand Up @@ -98,6 +100,10 @@ class Sample2Activity : AppCompatActivity() {
private var kdjChartFactory: KdjChartFactory? = null
private val kdjChartConfig = KdjChartConfig()

// rsi指标图工厂与配置
private var rsiChartFactory: RsiChartFactory? = null
private val rsiChartConfig = RsiChartConfig()

// 自定义示例图与配置
private var customChartFactory: CustomChartFactory? = null
private var customChartConfig = CustomChartConfig()
Expand Down Expand Up @@ -132,6 +138,7 @@ class Sample2Activity : AppCompatActivity() {
initTimeBar()
initMacdChart()
initKdjChart()
initRsiChart()
initCustomChart()

stockChartConfig.apply {
Expand All @@ -142,6 +149,7 @@ class Sample2Activity : AppCompatActivity() {
timeBarFactory!!,
macdChartFactory!!,
kdjChartFactory!!,
rsiChartFactory!!,
customChartFactory!!
)

Expand Down Expand Up @@ -251,7 +259,7 @@ class Sample2Activity : AppCompatActivity() {
}

// 图高度
height = DimensionUtil.dp2px(this@Sample2Activity, 250f)
height = DimensionUtil.dp2px(this@Sample2Activity, 200f)

// 左侧标签设置
leftLabelConfig = KChartConfig.LabelConfig(
Expand Down Expand Up @@ -285,7 +293,7 @@ class Sample2Activity : AppCompatActivity() {

volumeChartConfig.apply {
// 图高度
height = DimensionUtil.dp2px(this@Sample2Activity, 60f)
height = DimensionUtil.dp2px(this@Sample2Activity, 40f)


// 长按左侧标签配置
Expand Down Expand Up @@ -329,7 +337,7 @@ class Sample2Activity : AppCompatActivity() {

macdChartConfig.apply {
// 图高度
height = DimensionUtil.dp2px(this@Sample2Activity, 90f)
height = DimensionUtil.dp2px(this@Sample2Activity, 60f)

// 长按左侧标签配置
highlightLabelLeft = HighlightLabelConfig(
Expand All @@ -348,7 +356,7 @@ class Sample2Activity : AppCompatActivity() {

kdjChartConfig.apply {
// 图高度
height = DimensionUtil.dp2px(this@Sample2Activity, 90f)
height = DimensionUtil.dp2px(this@Sample2Activity, 60f)

// 长按左侧标签配置
highlightLabelLeft = HighlightLabelConfig(
Expand All @@ -357,7 +365,25 @@ class Sample2Activity : AppCompatActivity() {
padding = DimensionUtil.dp2px(this@Sample2Activity, 5f).toFloat()
)
}
}

/**
* rsi指标图初始化
*/
private fun initRsiChart() {
rsiChartFactory = RsiChartFactory(stock_chart, rsiChartConfig)

rsiChartConfig.apply {
// 图高度
height = DimensionUtil.dp2px(this@Sample2Activity, 60f)

// 长按左侧标签配置
highlightLabelLeft = HighlightLabelConfig(
textSize = DimensionUtil.sp2px(this@Sample2Activity, 10f).toFloat(),
bgColor = Color.parseColor("#A3A3A3"),
padding = DimensionUtil.dp2px(this@Sample2Activity, 5f).toFloat()
)
}
}

/**
Expand Down Expand Up @@ -538,7 +564,8 @@ class Sample2Activity : AppCompatActivity() {
this.kChartType = kChartType
kChartConfig.kChartType = this.kChartType
// 成交量图根据K线图类型决定是空心还是实心
volumeChartConfig.volumeChartType = if(this.kChartType is KChartConfig.KChartType.HOLLOW) VolumeChartConfig.VolumeChartType.HOLLOW() else VolumeChartConfig.VolumeChartType.CANDLE()
volumeChartConfig.volumeChartType =
if (this.kChartType is KChartConfig.KChartType.HOLLOW) VolumeChartConfig.VolumeChartType.HOLLOW() else VolumeChartConfig.VolumeChartType.CANDLE()
stock_chart.notifyChanged()
refreshOptionButtonsState()
}
Expand Down Expand Up @@ -588,7 +615,8 @@ class Sample2Activity : AppCompatActivity() {
Pair(index_ema, Index.EMA()),
Pair(index_boll, Index.BOLL()),
Pair(index_macd, Index.MACD()),
Pair(index_kdj, Index.KDJ())
Pair(index_kdj, Index.KDJ()),
Pair(index_rsi, Index.RSI())
)
)

Expand Down Expand Up @@ -621,6 +649,13 @@ class Sample2Activity : AppCompatActivity() {
stockChartConfig.addChildCharts(kdjChartFactory!!)
}
}
Index.RSI::class -> {
if (stockChartConfig.childChartFactories.contains(rsiChartFactory!!)) {
stockChartConfig.removeChildCharts(rsiChartFactory!!)
} else {
stockChartConfig.addChildCharts(rsiChartFactory!!)
}
}
}
stock_chart.notifyChanged()
refreshOptionButtonsState()
Expand Down Expand Up @@ -664,6 +699,10 @@ class Sample2Activity : AppCompatActivity() {
button.isSelected =
stockChartConfig.childChartFactories.contains(kdjChartFactory!!)
}
Index.RSI::class -> {
button.isSelected =
stockChartConfig.childChartFactories.contains(rsiChartFactory!!)
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions samples/src/main/res/layout/layout_sample2_option_buttons.xml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,13 @@
android:layout_height="match_parent"
android:text="KDJ" />

<TextView
android:id="@+id/index_rsi"
style="@style/OptionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="RSI" />

<TextView
android:id="@+id/custom"
style="@style/OptionButtonStyle"
Expand Down

0 comments on commit d10cb97

Please sign in to comment.