Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/src/main/java/s/yarlykov/fixdataproto/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ import android.util.Log
fun logIt(message: String, tag: String = "APP_TAG") {
Log.i(tag, message)
System.out.println("$tag: $message")
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import android.app.Application
import s.yarlykov.fixdataproto.R
import s.yarlykov.fixdataproto.data.BarMarketDataRepoImpl
import s.yarlykov.fixdataproto.data.FooMarketDataRepoImpl
import s.yarlykov.fixdataproto.domain.MarketDataHub
import s.yarlykov.fixdataproto.data.MarketDataHub
import s.yarlykov.fixdataproto.domain.MarketDataProvider
import s.yarlykov.fixdataproto.domain.MarketDataProviderImpl
import s.yarlykov.fixdataproto.domain.MarketDataRepo
import s.yarlykov.fixdataproto.data.MarketDataProviderImpl

class TradingApp : Application() {

Expand All @@ -16,9 +15,11 @@ class TradingApp : Application() {
override fun onCreate() {
super.onCreate()

val capacity = 30

val list = listOf<MarketDataProvider>(
MarketDataProviderImpl(getString(R.string.foo), FooMarketDataRepoImpl()),
MarketDataProviderImpl(getString(R.string.bar), BarMarketDataRepoImpl())
MarketDataProviderImpl(getString(R.string.foo), FooMarketDataRepoImpl(), capacity),
MarketDataProviderImpl(getString(R.string.bar), BarMarketDataRepoImpl(), capacity)
)

marketDataHub = MarketDataHub(list)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers
import s.yarlykov.fixdataproto.domain.MarketData
import s.yarlykov.fixdataproto.domain.MarketDataRepo
import s.yarlykov.fixdataproto.logIt
import java.util.concurrent.TimeUnit
import kotlin.random.Random

private const val PRICE_MIN = 50
private const val PRICE_MAX = 70
const val BAR_PRICE_MIN = 50
const val BAR_PRICE_MAX = 70

class BarMarketDataRepoImpl : MarketDataRepo() {

class BarMarketDataRepoImpl : MarketDataRepo {
override fun connect(): Observable<MarketData> =
Observable
.interval(1, TimeUnit.SECONDS, Schedulers.newThread())
.map {
MarketData(Random.nextInt(PRICE_MIN, PRICE_MAX))
}
.doOnNext {
logIt("${it.value} in ${it.time}")
MarketData(
Random.nextInt(BAR_PRICE_MIN, BAR_PRICE_MAX),
timeLineHandler.getMarker(System.currentTimeMillis())
)
}
.publish()
.refCount()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@ import s.yarlykov.fixdataproto.logIt
import java.util.concurrent.TimeUnit
import kotlin.random.Random

private const val PRICE_MIN = 1
private const val PRICE_MAX = 20
const val FOO_PRICE_MIN = 1
const val FOO_PRICE_MAX = 20

class FooMarketDataRepoImpl : MarketDataRepo {
class FooMarketDataRepoImpl : MarketDataRepo() {

override fun connect(): Observable<MarketData> =
Observable
.interval(1, TimeUnit.SECONDS, Schedulers.newThread())
.map {
MarketData(Random.nextInt(PRICE_MIN, PRICE_MAX))
MarketData(Random.nextInt(FOO_PRICE_MIN, FOO_PRICE_MAX),
timeLineHandler.getMarker(System.currentTimeMillis()))
}
.doOnNext {
logIt("${it.value} in ${it.time}")
logIt("${it.value} in ${it.marker.time}")
}
.publish()
.refCount()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package s.yarlykov.fixdataproto.domain
package s.yarlykov.fixdataproto.data

import io.reactivex.Observable
import s.yarlykov.fixdataproto.domain.Granularity
import s.yarlykov.fixdataproto.domain.MarketData
import s.yarlykov.fixdataproto.domain.MarketDataProvider

class MarketDataHub(providers: List<MarketDataProvider>) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package s.yarlykov.fixdataproto.domain
package s.yarlykov.fixdataproto.data

import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.disposables.Disposable
import io.reactivex.subjects.BehaviorSubject
import s.yarlykov.fixdataproto.domain.Granularity
import s.yarlykov.fixdataproto.domain.MarketData
import s.yarlykov.fixdataproto.domain.MarketDataProvider
import s.yarlykov.fixdataproto.domain.MarketDataRepo
import s.yarlykov.fixdataproto.domain.time.TimeEvent
import s.yarlykov.fixdataproto.domain.time.TimeLineMarker

/**
* Класс реализует двусвязный список на массиве. Массив удобен для первичной инииализации.
Expand All @@ -19,7 +25,12 @@ class MarketDataProviderImpl(

// Массив для хранения котировок
private var history: Array<Link> = Array(capacity) { index ->
Link(index, MarketData(0), null, null)
Link(
index,
MarketData(0, TimeLineMarker(0, TimeEvent.SECOND)),
null,
null
)
}

// Этот указатель будет передвигаться по кругу и указывать
Expand All @@ -38,7 +49,7 @@ class MarketDataProviderImpl(
override fun onNext(fixData: MarketData) {
head.marketData = fixData
head = head.next!!
aggregatedDataStream.onNext(collectAscent())
aggregatedDataStream.onNext(headIsPastTailIsNow())
}

override fun onError(e: Throwable) {
Expand Down Expand Up @@ -78,7 +89,7 @@ class MarketDataProviderImpl(
}

// Список котировок по убывающей дате
private fun collectDescent(): List<MarketData> {
private fun headIsNowTailIsPast(): List<MarketData> {

val list = mutableListOf<MarketData>()

Expand All @@ -94,7 +105,7 @@ class MarketDataProviderImpl(
}

// Список котировок по возрастающей дате
private fun collectAscent() : List<MarketData> {
private fun headIsPastTailIsNow(): List<MarketData> {
val list = mutableListOf<MarketData>()

var item = head
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package s.yarlykov.fixdataproto.domain

data class ChartOptions(
val title : String,
val axisX : String,
val axisY: String,
val min : Int,
val max : Int)
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
package s.yarlykov.fixdataproto.domain

data class MarketData(val value : Int, val time : Long = System.currentTimeMillis())
import s.yarlykov.fixdataproto.domain.time.TimeLineMarker

data class MarketData(
val value: Int,
val marker: TimeLineMarker
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package s.yarlykov.fixdataproto.domain

import io.reactivex.Observable
import s.yarlykov.fixdataproto.domain.time.TimeLineHandler

interface MarketDataRepo {
fun connect() : Observable<MarketData>
abstract class MarketDataRepo {

val timeLineHandler = TimeLineHandler()

abstract fun connect(): Observable<MarketData>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package s.yarlykov.fixdataproto.domain.time

enum class TimeEvent(val value : Int) {
SECOND(1),
MINUTE(60),
HOUR(3600),
DAY(24 * 60 * 60)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package s.yarlykov.fixdataproto.domain.time

import java.text.SimpleDateFormat
import java.util.*

class TimeLineHandler(startTime: Long = System.currentTimeMillis()) {

private val timeFormat = "dd-HH-mm-ss"

private val day = 0
private val hour = 1
private val minute = 2

private val parsedStartTime = parseTime(startTime)

private var lastDay: Int = parsedStartTime[day]
private var lastHour: Int = parsedStartTime[hour]
private var lastMinute: Int = parsedStartTime[minute]

/**
* Вернуть маркер, который клеится к маркет дате
*/
fun getMarker(time: Long): TimeLineMarker =
TimeLineMarker(time, getEvent(time))

/**
* Определить произошел ли переход дня/часа/минуты
* Переход дня подразумевает также переход часа и минуты,
* а переход часа - переход минуты.
*/
private fun getEvent(time: Long): TimeEvent {
val currentTime = parseTime(time)

return if (currentTime[day] != lastDay) {
lastDay = currentTime[day]
TimeEvent.DAY
} else if (currentTime[hour] != lastHour) {
lastHour = currentTime[hour]
TimeEvent.HOUR
} else if (currentTime[minute] != lastMinute) {
lastMinute = currentTime[minute]
TimeEvent.MINUTE
} else {
TimeEvent.SECOND
}
}

private fun parseTime(time: Long): List<Int> {
val sdf = SimpleDateFormat(timeFormat, Locale.getDefault())
return sdf
.format(time)
.split("-".toRegex())
.map {
it.toInt()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package s.yarlykov.fixdataproto.domain.time

data class TimeLineMarker(val time: Long, val timeEvent: TimeEvent)
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.activity_main.*
import s.yarlykov.fixdataproto.R
import s.yarlykov.fixdataproto.application.TradingApp
import s.yarlykov.fixdataproto.data.FOO_PRICE_MAX
import s.yarlykov.fixdataproto.data.FOO_PRICE_MIN
import s.yarlykov.fixdataproto.domain.ChartOptions
import s.yarlykov.fixdataproto.domain.MarketData
import java.text.SimpleDateFormat
import java.util.*
Expand All @@ -25,13 +28,22 @@ class MainActivity : AppCompatActivity() {

val hub = (application as TradingApp).getHub()

graph.setChartOptions(ChartOptions(
getString(R.string.foo),
"x",
"y",
FOO_PRICE_MIN,
FOO_PRICE_MAX
))

disposable.add(
hub
.marketDataStream(getString(R.string.foo))
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
val message = it.print()
tvFoo.text = message
graph.update(it)
}
)

Expand All @@ -55,11 +67,10 @@ class MainActivity : AppCompatActivity() {

val sdf = SimpleDateFormat("ss", Locale.getDefault())


val li = mutableListOf<String>()
this.forEach {md ->
if(md.value > 0) {
val s = "${"%02d".format(md.value)}: ${sdf.format(md.time)}s"
val s = "${"%02d".format(md.value)}: ${sdf.format(md.marker.time)}s"
li.add(s)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package s.yarlykov.fixdataproto.presentation.chart

import s.yarlykov.fixdataproto.domain.ChartOptions
import s.yarlykov.fixdataproto.domain.MarketData

interface ChartView {
fun setChartOptions(options : ChartOptions)
fun update(data : List<MarketData>)
}
Loading