Bankroll report update

feature/top10
Laurent 7 years ago
parent 8f3bd78f49
commit a272986b6c
  1. 14
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt
  2. 47
      app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollCalculator.kt
  3. 165
      app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReport.kt
  4. 11
      app/src/main/java/net/pokeranalytics/android/calculus/interfaces/Datable.kt
  5. 15
      app/src/main/java/net/pokeranalytics/android/model/interfaces/Dated.kt
  6. 7
      app/src/main/java/net/pokeranalytics/android/model/realm/Transaction.kt
  7. 24
      app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt

@ -14,6 +14,7 @@ import net.pokeranalytics.android.util.extensions.formatted
import net.pokeranalytics.android.util.extensions.formattedHourlyDuration
import net.pokeranalytics.android.util.extensions.toCurrency
import java.util.*
import kotlin.math.exp
class StatFormattingException(message: String) : Exception(message) {
@ -128,6 +129,19 @@ enum class Stat : RowRepresentable {
return netBB / numberOfHands * 100
}
fun riskOfRuin(hourlyRate: Double, hourlyStandardDeviation: Double, bankrollValue: Double) : Double? {
if (bankrollValue <= 0.0) {
return null
}
val numerator = -2 * hourlyRate * bankrollValue
val denominator = Math.pow(hourlyStandardDeviation, 2.0)
val ratio = numerator / denominator
return exp(ratio)
}
}
override val resId: Int?

@ -1,9 +1,14 @@
package net.pokeranalytics.android.calculus.bankroll
import io.realm.Realm
import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.ComputableGroup
import net.pokeranalytics.android.calculus.ComputedResults
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.model.realm.TransactionType
class BankrollCalculator {
@ -14,22 +19,58 @@ class BankrollCalculator {
val realm = Realm.getDefaultInstance()
val report = BankrollReport(setup)
val useRatedValues = (setup.bankroll == null)
val sessions = Filter.queryOn<Session>(realm, setup.queryConditions)
val transactions = Filter.queryOn<Transaction>(realm, setup.queryConditions)
val queryConditions = setup.queryConditions
val sessions = Filter.queryOn<Session>(realm, queryConditions)
val transactions = Filter.queryOn<Transaction>(realm, queryConditions)
val sessionsNet = sessions.sum("result.net")
val transactionsNet = transactions.sum("value")
report.addDatedItems(transactions)
transactions.forEach {
report.addTransaction(it)
}
val group = ComputableGroup("", queryConditions, listOf(Stat.NET_RESULT, Stat.HOURLY_RATE, Stat.STANDARD_DEVIATION_HOURLY))
val result = Calculator.compute(realm, group, Calculator.Options())
result.computedStat(Stat.NET_RESULT)?.let {
report.netResult = it.value
}
report.transactionsNet = transactionsNet.toDouble()
this.computeRiskOfRuin(report, result)
val depositType = TransactionType.getByValue(TransactionType.Value.DEPOSIT, realm)
report.transactionBuckets[depositType.id]?.let { bucket ->
report.depositTotal = bucket.transactions.sumByDouble { it.amount }
}
val withdrawalType = TransactionType.getByValue(TransactionType.Value.WITHDRAWAL, realm)
report.transactionBuckets[withdrawalType.id]?.let { bucket ->
report.withdrawalTotal = bucket.transactions.sumByDouble { it.amount }
}
realm.close()
return report
}
fun computeRiskOfRuin(report: BankrollReport, results: ComputedResults) {
val hourlyRate = results.computedStat(Stat.HOURLY_RATE)?.value
val hourlyStandardDeviation = results.computedStat(Stat.STANDARD_DEVIATION_HOURLY)?.value
if (hourlyRate != null && hourlyStandardDeviation != null) {
report.riskOfRuin = Stat.riskOfRuin(hourlyRate, hourlyStandardDeviation, report.total)
}
}
}
}

@ -1,72 +1,12 @@
package net.pokeranalytics.android.calculus.bankroll
import net.pokeranalytics.android.calculus.interfaces.DatableValue
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.interfaces.DatedValue
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Transaction
import java.util.*
import kotlin.collections.HashMap
/**
* A class describing the parameters required to launch a bankroll report
*
*/
class BankrollReportSetup(val bankroll: Bankroll?, val from: Date? = null, val to: Date? = null) {
val queryConditions: List<QueryCondition>
get() {
val conditions = mutableListOf<QueryCondition>()
this.bankroll?.let {
val bankrollCondition = QueryCondition.AnyBankroll()
bankrollCondition.setObject(it)
conditions.add(bankrollCondition)
}
this.from?.let {
val fromCondition = QueryCondition.StartedFromDate()
fromCondition.singleValue = it
conditions.add(fromCondition)
}
this.to?.let {
val toCondition = QueryCondition.StartedToDate()
toCondition.singleValue = it
conditions.add(toCondition)
}
return conditions
}
}
class TransactionBucket(useRate: Boolean = false) {
var transactions: MutableList<Transaction> = mutableListOf()
private set
var total: Double = 0.0
private set
var useRate: Boolean = useRate
private set
fun addTransaction(transaction: Transaction) {
this.transactions.add(transaction)
var rate = 1.0
if (this.useRate) {
rate = transaction.bankroll?.currency?.rate ?: 1.0
}
val ratedAmount = rate * transaction.amount
this.total += ratedAmount
}
}
class BRGraphPoint {
var value: Double = 0.0
var variation: Double = 0.0
var date: Date? = null
}
class BankrollReport(setup: BankrollReportSetup) {
@ -85,7 +25,37 @@ class BankrollReport(setup: BankrollReportSetup) {
* The net result from poker computables
*/
var netResult: Double = 0.0
private set
set(value) {
field = value
total = this.netResult + this.transactionsNet
}
/**
* The net result from transactions
*/
var transactionsNet: Double = 0.0
set(value) {
field = value
total = this.netResult + this.transactionsNet
}
/**
* The sum of all deposits
*/
var depositTotal: Double = 0.0
set(value) {
field = value
this.netBanked = this.depositTotal + this.withdrawalTotal
}
/**
* The sum of all withdrawals
*/
var withdrawalTotal: Double = 0.0
set(value) {
field = value
this.netBanked = this.depositTotal + this.withdrawalTotal
}
/**
* The difference between withdrawals and deposits
@ -96,16 +66,21 @@ class BankrollReport(setup: BankrollReportSetup) {
/**
* The risk of ruin
*/
var riskOfRuin: Double = 0.0
private set
var riskOfRuin: Double? = null
var transactions: List<Transaction> = mutableListOf()
private set
var transactionBuckets: HashMap<String, TransactionBucket> = HashMap()
private set
var evolutionPoints: MutableList<BRGraphPoint> = mutableListOf()
var evolutionItems: MutableList<DatedValue> = mutableListOf()
private set
var evolutionPoints: Array<BRGraphPoint> = arrayOf()
var evolutionItems: Array<DatableValue> = arrayOf()
fun addDatedItems(items: Collection<DatedValue>) {
this.evolutionItems.addAll(items)
}
fun addTransaction(transaction: Transaction) {
@ -127,5 +102,63 @@ class BankrollReport(setup: BankrollReportSetup) {
}
}
/**
* A class describing the parameters required to launch a bankroll report
*
*/
class BankrollReportSetup(val bankroll: Bankroll?, val from: Date? = null, val to: Date? = null) {
val queryConditions: List<QueryCondition>
get() {
val conditions = mutableListOf<QueryCondition>()
this.bankroll?.let {
val bankrollCondition = QueryCondition.AnyBankroll()
bankrollCondition.setObject(it)
conditions.add(bankrollCondition)
}
this.from?.let {
val fromCondition = QueryCondition.StartedFromDate()
fromCondition.singleValue = it
conditions.add(fromCondition)
}
this.to?.let {
val toCondition = QueryCondition.StartedToDate()
toCondition.singleValue = it
conditions.add(toCondition)
}
return conditions
}
}
class TransactionBucket(useRate: Boolean = false) {
var transactions: MutableList<Transaction> = mutableListOf()
private set
var total: Double = 0.0
private set
var useRate: Boolean = useRate
private set
fun addTransaction(transaction: Transaction) {
this.transactions.add(transaction)
var rate = 1.0
if (this.useRate) {
rate = transaction.bankroll?.currency?.rate ?: 1.0
}
val ratedAmount = rate * transaction.amount
this.total += ratedAmount
}
}
data class BRGraphPoint(var value: Double = 0.0, var date: Date? = null, var data: Any? = null) {
var variation: Double = 0.0
}

@ -1,11 +0,0 @@
package net.pokeranalytics.android.calculus.interfaces
import java.util.*
interface Datable {
var date: Date
}
interface DatableValue : Datable {
var value: Double
}

@ -0,0 +1,15 @@
package net.pokeranalytics.android.model.interfaces
import java.util.*
interface Dated {
var date: Date
}
interface DatedValue : Dated {
var amount: Double
}

@ -7,6 +7,7 @@ import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.interfaces.DatedValue
import net.pokeranalytics.android.model.interfaces.Manageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
@ -17,7 +18,7 @@ import java.util.*
import kotlin.collections.ArrayList
open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Filterable {
open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Filterable, DatedValue {
companion object {
val rowRepresentation: List<RowRepresentable> by lazy {
@ -42,10 +43,10 @@ open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSo
var bankroll: Bankroll? = null
// The amount of the transaction
var amount: Double = 0.0
override var amount: Double = 0.0
// The date of the transaction
var date: Date = Date()
override var date: Date = Date()
// The type of the transaction
var type: TransactionType? = null

@ -14,13 +14,29 @@ import kotlin.collections.ArrayList
open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentableDataSource, RowRepresentable {
enum class Value {
WITHDRAWAL,
DEPOSIT,
BONUS
}
companion object {
val rowRepresentation : List<RowRepresentable> by lazy {
val rowRepresentation: List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TransactionTypeRow.values())
rows
}
fun getByValue(value: Value, realm: Realm): TransactionType {
val type = realm.where(TransactionType::class.java).equalTo("kind", value.ordinal).findFirst()
type?.let {
return it
}
throw IllegalStateException("Transaction type ${value.name} should exist in database!")
}
}
@PrimaryKey
@ -43,7 +59,7 @@ open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentab
}
override fun adapterRows(): List<RowRepresentable>? {
return TransactionType.rowRepresentation
return rowRepresentation
}
override fun stringForRow(row: RowRepresentable): String {
@ -72,7 +88,3 @@ open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentab
}
}
enum class TransactionKind {
WITHDRAWAL,
DEPOSIT
}

Loading…
Cancel
Save