FreeBit
Member
Offline
Activity: 106
Merit: 10
|
|
January 20, 2015, 10:01:02 PM |
|
Nächstes Beispiel. Die Werte des Währungspaars fasse ich in einer Klasse zusammen: /* base/counter currency pair class and its companion object */ object BCPair extends XMLTools { def apply(b: Double, c: Double) = new BCPair(b, c) def apply(bcp: BCPair) = new BCPair(bcp.b, bcp.c) def apply() = new BCPair() def apply(xml: Elem) = new BCPair( b = tDbl(xml \ "base"), c = tDbl(xml \ "counter")) val zero = BCPair(0, 0) val error = BCPair(-1, -1) }
class BCPair (var b: Double = 0, var c: Double = 0) {
/* data manipulation */ def set(in: (Double, Double)) {b = in._1; c = in._2} def set(bcp: BCPair) {b = bcp.b; c = bcp.c} def set(bb: Double, cc: Double) {b = bb; c = cc}
/* abs, rounding*/ def abs = BCPair(scala.math.abs(b), scala.math.abs(c)) def rnd(decs: DecSet) = BCPair( b = decs.rndBase(b), c = decs.rndCntr(c) )
/* check conditions */ def cndAND (f: Double => Boolean) = f(b) && f(c) def cndOR (f: Double => Boolean) = f(b) || f(c)
/* standard operators */ def + (that: BCPair) = new BCPair(this.b + that.b, this.c + that.c) def - (that: BCPair) = new BCPair(this.b - that.b, this.c - that.c) def * (d: Double) = new BCPair(this.b * d, this.c * d) def / (d: Double) = new BCPair(this.b / d, this.c / d) def isEqual (that: BCPair) = this.b == that.b && this.c == that.c
/* calc the rate: i * r = c <=> r = c / i */ def calcRate = if (b != 0) scala.math.abs(c / b) else -1D
/* delivers min/max values of both entries */ def mergeMax(that: BCPair) = BCPair( b = tools.max(b, that.b), c = tools.max(c, that.c) )
def mergeMinPos(that: BCPair) = { def oz(x: Double, y: Double) = (x > 0, y > 0) match { case (true, true) => tools.min(x, y) case (false, true) => y case (true, false) => x case (false, false) => 0D } BCPair(b = oz(b, that.b), c = oz(c, that.c)) }
/* formatted output */ def print = "base:" + b + " cntr:" + c
def toStr( bcu: BCUnits, decB: Int, decC: Int) = fmtAmt(b, bcu.b, decB) + " | " + fmtAmt(c, bcu.c, decC)
def toStr( bcu: BCUnits, fmtB: Double => String, fmtC: Double => String) = fmtAmt(b, bcu.b, fmtB) + " | " + fmtAmt(c, bcu.c, fmtC)
def toStr(decs: Decimals, units: BCUnits): String = toStr(bcu = units, decB = decs.decBase, decC = decs.decCntr)
def toStr(decs: DecSet, units: BCUnits): String = toStr(bcu = units, decB = decs.decBase, decC = decs.decCntr)
/* XML output */ def toXML = fXML(b.toString, c.toString) def toXML(decs: DecSet) = fXML(decs.fmtBase(b), decs.fmtCntr(c)) private def fXML(sb: String, sc: String) = <bcpair><base>{sb}</base><counter>{sc}</counter></bcpair>
/* helper functions */ private def cLen(s: String) = {if (s.indexOf("-") < 0) 1 else 0} + s.length
private def fmtAmt(v: Double, unit: String, fmt: Double => String) = { val s = fmt(v) tools.pst( cLen(s), s) + " " + unit }
private def fmtAmt(v: Double, unit: String, dec: Int) = { val s = tools.format(v, dec) tools.pst( cLen(s), s) + " " + unit } }
Auch etwas länglich, aber ich kann jetzt ... // ... hiermit beispielsweise zwei Handelergebnisse aufsummieren. val a = BCPair(b = 1, c = 100) val b = BCPair(2, -30) val c = a + b // wäre hier BCPair(3, 70)
// und mit der toStr-Methode ins Logfile schreiben log.trade("trade result -> " + c.toStr(decs.calc, ...)
// oder testen, ob beide werte positiv sind if (c.cndAND (v => v > 0)) { ... }
Das erspart auch Arbeit bei der Deklaration von Klassen, beispielsweise einer Klasse, die die Handelsresultate aufnimmt: /* the IFExTradeData class itself */ case class IFExTradeData ( dbid: Int, typ: TTrdDir.TTrdDir, bcu: BCUnits, timestamp: Long, tradeid: Long, orderid: Long, resultWOF: BCPair, resultWF: BCPair, fees: BCPair, rateWOF: Double, rateWF: Double) extends IFExDataBase(dbid) {
/* for error messages */ override val errorClassName = "IFExTradeData"
/* check on equality */ def isEqual(that: IFExTradeData) = dbid == that.dbid && typ == that.typ && bcu == that.bcu && timestamp == that.timestamp && tradeid == that.tradeid && orderid == that.orderid && resultWOF.isEqual(that.resultWOF) && resultWF.isEqual(that.resultWF) && fees.isEqual(that.fees) && rateWOF == that.rateWOF && rateWF == that.rateWF
/* type to string */ def typStr = TTrdDir.toStr(typ)
/* delivers a copy with setting of a changed database id */ def copyWithDBID(id: Int) = copy(dbid = id)
/* build log string */ def toLog( indent: String, decs: DecSet) = {
def strBCP(bcp: BCPair) = bcp.toStr( bcu, decs.fmtBase _, decs.fmtCntr _)
List( "TRADEDATA", indent + "typ : " + typStr.toUpperCase, indent + "orderid : " + orderid, indent + "tradeid : " + tradeid, indent + "timestamp : " + tools.dateToString(timestamp), indent + "res w/o fee : " + strBCP(resultWOF), indent + "res w fee : " + strBCP(resultWF), indent + "fees : " + strBCP(fees), indent + "rate w/o fee : " + fmtValue(rateWOF, decs.fmtRate), indent + "rate w fee : " + fmtValue(rateWF, decs.fmtRate)).mkString("\n") }
/* creates a name/value map for database storing */ override def dbValues(tableName: String, secID: Int) = Map( ("TableName", tableName), ("PrimaryKeyName", pkName), ("PrimaryKeyValue", dbid), ("secid", secID), ("typ", typStr), ("base", bcu.b), ("cntr", bcu.c), ("timestamp", timestamp), ("tradeid", tradeid), ("orderid", orderid), ("ratewof", rateWOF), ("ratewf", rateWF)) ++ mapBCP("resultwof", resultWOF) ++ mapBCP("resultwf", resultWF) ++ mapBCP("fees", fees)
/* stores to database, only if not exists */ override def store(db: Database, table: String, secID: Int) =
/* checks if dataset already exists */ db.selectFromDB( table, "where tradeid=" + tradeid, "") match {
/* dataset retrieved --> no action */ case rs: ResultSet if rs.next() => rs.close()
/* no dataset found --> store */ case rs: ResultSet => super.store(db, table, secID); rs.close() case _ => super.store(db, table, secID) }
}
Wieder alles etwas länglich, aber sehr nützlich für die einheitliche Behandlung der Daten von verschiedenen Exchanges.
|