diff --git a/Dockerfile b/Dockerfile index 73cb9cf7f..aaf01941a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,6 +21,7 @@ ENV EXCHANGE null ENV TradedPair BTC/USD ENV WebClientUsername NULL ENV WebClientPassword NULL +ENV WebClientListenPort 3000 # IP to access mongo instance. If you are on a mac, run `boot2docker ip` and replace `tribeca-mongo`. ENV MongoDbUrl mongodb://tribeca-mongo:27017/tribeca diff --git a/sample-dev-tribeca.json b/sample-dev-tribeca.json index 7e3958aac..0f4719328 100644 --- a/sample-dev-tribeca.json +++ b/sample-dev-tribeca.json @@ -5,6 +5,7 @@ "MongoDbUrl": "mongodb://localhost:27017/tribeca", "WebClientUsername": "NULL", "WebClientPassword": "NULL", + "WebClientListenPort": "3000", "HitBtcPullUrl": "http://demo-api.hitbtc.com", "HitBtcOrderEntryUrl": "ws://demo-api.hitbtc.com:8080", diff --git a/sample-prod-tribeca.json b/sample-prod-tribeca.json index b7ead9126..e915138dd 100644 --- a/sample-prod-tribeca.json +++ b/sample-prod-tribeca.json @@ -5,6 +5,7 @@ "MongoDbUrl": "mongodb://localhost:27017/tribeca", "WebClientUsername": "NULL", "WebClientPassword": "NULL", + "WebClientListenPort": "3000", "HitBtcPullUrl": "http://api.hitbtc.com", "HitBtcOrderEntryUrl": "wss://api.hitbtc.com:8080", diff --git a/src/common/models.ts b/src/common/models.ts index 8882e0a4e..efa83f777 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -261,7 +261,7 @@ export class PositionReport { public value: number, public quoteValue: number, public pair: CurrencyPair, - public exch: Exchange, + public exchange: Exchange, public time: moment.Moment) {} } diff --git a/src/service/backtest.ts b/src/service/backtest.ts index abccf25a3..a78431515 100644 --- a/src/service/backtest.ts +++ b/src/service/backtest.ts @@ -276,7 +276,7 @@ export class BacktestParameters { id: string; } -export class BacktestPersister implements Persister.ILoadAllByExchangeAndPair, Persister.ILoadLatest { +export class BacktestPersister implements Persister.ILoadAll, Persister.ILoadLatest { public load = (exchange: Models.Exchange, pair: Models.CurrencyPair, limit: number = null): Q.Promise => { return this.loadAll(limit); }; diff --git a/src/service/broker.ts b/src/service/broker.ts index 8c02a7c35..4dde27ec8 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -334,12 +334,6 @@ export class OrderBroker implements Interfaces.IOrderBroker { } } -export class PositionPersister extends Persister.Persister { - constructor(db) { - super(db, "pos", Persister.timeLoader, Persister.timeSaver); - } -} - export class PositionBroker implements Interfaces.IPositionBroker { private _log : Utils.Logger; diff --git a/src/service/main.ts b/src/service/main.ts index dbb021cb9..a1821943a 100644 --- a/src/service/main.ts +++ b/src/service/main.ts @@ -88,8 +88,7 @@ var backTestSimulationSetup = (inputData : Array(topic: string) : Messaging.IReceive => new Messaging.NullReceiver(); - var getPersister = (collectionName: string) : Persister.ILoadAllByExchangeAndPair => new Backtest.BacktestPersister(); - var getMarketTradePersister = () => getPersister("mt"); + var getPersister = (collectionName: string) : Persister.ILoadAll => new Backtest.BacktestPersister(); var getRepository = (defValue: T, collectionName: string) : Persister.ILoadLatest => new Backtest.BacktestPersister([defValue]); @@ -104,7 +103,6 @@ var backTestSimulationSetup = (inputData : Array { app.use(compression()); app.use(express.static(path.join(__dirname, "admin"))); - http_server.listen(3000, () => mainLog('Listening to admins on *:3000...')); + http_server.listen(config.GetNumber("WebClientListenPort"), () => mainLog('Listening to admins on *:3000...')); var getExchange = (): Models.Exchange => { var ex = config.GetString("EXCHANGE").toLowerCase(); @@ -167,12 +165,16 @@ var liveTradingSetup = () => { var db = Persister.loadDb(config); - var getPersister = (collectionName: string) : Persister.ILoadAllByExchangeAndPair => - new Persister.BasicPersister(db, collectionName); - var getMarketTradePersister = () : Persister.ILoadAllByExchangeAndPair => new MarketTrades.MarketTradePersister(db); + var loaderSaver = new Persister.LoaderSaver(exchange, pair); + var mtLoaderSaver = new MarketTrades.MarketTradesLoaderSaver(loaderSaver); + + var getPersister = (collectionName: string) : Persister.ILoadAll => { + var ls = collectionName === "mt" ? mtLoaderSaver : loaderSaver; + return new Persister.Persister(db, collectionName, exchange, pair, ls.loader, ls.saver); + }; var getRepository = (defValue: T, collectionName: string) : Persister.ILoadLatest => - new Persister.RepositoryPersister(db, defValue, collectionName); + new Persister.RepositoryPersister(db, defValue, collectionName, exchange, pair, loaderSaver.loader, loaderSaver.saver); var classes : SimulationClasses = { exchange: exchange, @@ -182,7 +184,6 @@ var liveTradingSetup = () => { getExch: getExch, getReceiver: getReceiver, getPersister: getPersister, - getMarketTradePersister: getMarketTradePersister, getRepository: getRepository, getPublisher: getPublisher }; @@ -196,8 +197,7 @@ interface SimulationClasses { timeProvider: Utils.ITimeProvider; getExch(orderCache: Broker.OrderStateCache): Interfaces.CombinedGateway; getReceiver(topic: string) : Messaging.IReceive; - getPersister(collectionName: string) : Persister.ILoadAllByExchangeAndPair; - getMarketTradePersister() : Persister.ILoadAllByExchangeAndPair; + getPersister(collectionName: string) : Persister.ILoadAll; getRepository(defValue: T, collectionName: string) : Persister.ILoadLatest; getPublisher(topic: string, persister?: Persister.ILoadAll): Messaging.IPublish; } @@ -207,7 +207,7 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { var orderPersister = getPersister("osr"); var tradesPersister = getPersister("trades"); var fairValuePersister = getPersister("fv"); - var mktTradePersister = classes.getMarketTradePersister(); + var mktTradePersister = getPersister("mt"); var positionPersister = getPersister("pos"); var messagesPersister = getPersister("msg"); var rfvPersister = getPersister("rfv"); @@ -222,9 +222,9 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { var completedSuccessfully = Q.defer(); Q.all([ - orderPersister.load(exchange, pair, 25000), - tradesPersister.load(exchange, pair, 10000), - mktTradePersister.load(exchange, pair, 100), + orderPersister.loadAll(25000), + tradesPersister.loadAll(10000), + mktTradePersister.loadAll(100), messagesPersister.loadAll(50), paramsPersister.loadLatest(), activePersister.loadLatest(), diff --git a/src/service/markettrades.ts b/src/service/markettrades.ts index afd29b745..d5f72cc35 100644 --- a/src/service/markettrades.ts +++ b/src/service/markettrades.ts @@ -14,36 +14,22 @@ import Broker = require("./broker"); import mongodb = require('mongodb'); import Web = require("./web"); -var loader = (d: Models.ExchangePairMessage) => { - if (d instanceof Models.MarketTrade) { - P.timeLoader(d); - return; +export class MarketTradesLoaderSaver { + public loader = (x : Models.MarketTrade) => { + this._wrapped.loader(x); + + if (typeof x.quote !== "undefined") + this._wrapped.loader(x.quote); } - if (d.data === null) return; - P.timeLoader(d.data); - - if (d.data.quote === null) return; - P.timeLoader(d.data.quote); -}; - -var saver = (d: Models.ExchangePairMessage) => { - if (d instanceof Models.MarketTrade) { - P.timeSaver(d); - return; + public saver = (x : Models.MarketTrade) => { + this._wrapped.saver(x); + + if (typeof x.quote !== "undefined") + this._wrapped.saver(x.quote); } - if (d.data === null) return; - P.timeSaver(d.data); - - if (d.data.quote === null) return; - P.timeSaver(d.data.quote); -}; - -export class MarketTradePersister extends P.Persister { - constructor(db: Q.Promise) { - super(db, "mt", P.timeLoader, P.timeSaver); - } + constructor(private _wrapped: P.LoaderSaver) {} } export class MarketTradeBroker implements Interfaces.IMarketTradeBroker { @@ -88,13 +74,9 @@ export class MarketTradeBroker implements Interfaces.IMarketTradeBroker { private _quoteEngine: Agent.QuotingEngine, private _base: Broker.ExchangeBroker, private _persister: P.IPersist, - initMkTrades: Array | Models.MarketTrade>) { - initMkTrades.forEach(t => { - if (t instanceof Models.MarketTrade) - this.marketTrades.push(t); - else - this.marketTrades.push((t).data); - }); + initMkTrades: Array) { + + initMkTrades.forEach(t => this.marketTrades.push(t)); this._log("loaded %d market trades", this.marketTrades.length); _marketTradePublisher.registerSnapshot(() => _.last(this.marketTrades, 50)); diff --git a/src/service/persister.ts b/src/service/persister.ts index 8429268a1..0114f7f2c 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -13,7 +13,7 @@ import moment = require('moment'); import Interfaces = require("./interfaces"); import Config = require("./config"); -export function loadDb(config : Config.IConfigProvider) { +export function loadDb(config: Config.IConfigProvider) { var deferred = Q.defer(); mongodb.MongoClient.connect(config.GetString("MongoDbUrl"), (err, db) => { if (err) deferred.reject(err); @@ -22,14 +22,32 @@ export function loadDb(config : Config.IConfigProvider) { return deferred.promise; } -export function timeLoader(x) { - if (typeof x.time !== "undefined") - x.time = moment.isMoment(x.time) ? x.time : moment(x.time); +export interface Persistable { + time?: moment.Moment|Date; + pair?: Models.CurrencyPair; + exchange?: Models.Exchange; } -export function timeSaver(x) { - if (typeof x.time !== "undefined") - x.time = (moment.isMoment(x.time) ? x.time : moment(x.time)).toDate(); +export class LoaderSaver { + public loader = (x: Persistable) => { + if (typeof x.time !== "undefined") + x.time = moment.isMoment(x.time) ? x.time : moment(x.time); + if (typeof x.exchange === "undefined") + x.exchange = this._exchange; + if (typeof x.pair === "undefined") + x.pair = this._pair; + } + + public saver = (x: Persistable) => { + if (typeof x.time !== "undefined") + x.time = (moment.isMoment(x.time) ? x.time : moment(x.time)).toDate(); + if (typeof x.exchange === "undefined") + x.exchange = this._exchange; + if (typeof x.pair === "undefined") + x.pair = this._pair; + } + + constructor(private _exchange: Models.Exchange, private _pair: Models.CurrencyPair) { } } export interface IPersist { @@ -44,18 +62,15 @@ export interface ILoadAll extends IPersist { loadAll(limit?: number, start_time?: moment.Moment): Q.Promise; } -export interface ILoadAllByExchangeAndPair extends ILoadAll { - load(exchange: Models.Exchange, pair: Models.CurrencyPair, limit: number): Q.Promise; -} - -export class RepositoryPersister implements ILoadLatest { +export class RepositoryPersister implements ILoadLatest { _log: Utils.Logger = Utils.log("tribeca:exchangebroker:repopersister"); public loadLatest = (): Q.Promise => { var deferred = Q.defer(); this.collection.then(coll => { - coll.find({}, { fields: { _id: 0 } }).limit(1).sort({ $natural: -1 }).toArray((err, arr) => { + var selector = { exchange: this._exchange, pair: this._pair }; + coll.find(selector, { fields: { _id: 0 } }).limit(1).sort({ $natural: -1 }).toArray((err, arr) => { if (err) { deferred.reject(err); } @@ -64,8 +79,7 @@ export class RepositoryPersister implements ILoadLatest { } else { var v = _.defaults(arr[0], this._defaultParameter); - if (v.hasOwnProperty("time")) - timeLoader(v); + this._loader(v); deferred.resolve(v); } }); @@ -75,11 +89,9 @@ export class RepositoryPersister implements ILoadLatest { }; public persist = (report: T) => { + this._saver(report); this.collection.then(coll => { - var v = report; - if (v.hasOwnProperty("time")) - timeSaver(v); - coll.insert(v, err => { + coll.insert(report, err => { if (err) this._log("Unable to insert into %s %s; %o", this._dbName, report, err); }); @@ -90,25 +102,24 @@ export class RepositoryPersister implements ILoadLatest { constructor( db: Q.Promise, private _defaultParameter: T, - private _dbName: string) { + private _dbName: string, + private _exchange: Models.Exchange, + private _pair: Models.CurrencyPair, + private _loader: (p: Persistable) => void, + private _saver: (p: Persistable) => void) { this.collection = db.then(db => db.collection(this._dbName)); } } -export class Persister implements ILoadAllByExchangeAndPair { +export class Persister implements ILoadAll { _log: Utils.Logger = Utils.log("tribeca:exchangebroker:persister"); - public load = (exchange: Models.Exchange, pair: Models.CurrencyPair, limit: number = null): Q.Promise => { - var selector = { exchange: exchange, pair: pair }; - return this.loadInternal(selector, limit); - }; - public loadAll = (limit?: number, start_time?: moment.Moment): Q.Promise => { - var selector = {}; + var selector = { exchange: this._exchange, pair: this._pair }; if (start_time) { - selector["time"] = {$gte: start_time.toDate()}; + selector["time"] = { $gte: start_time.toDate() }; } - + return this.loadInternal(selector, limit); }; @@ -123,7 +134,7 @@ export class Persister implements ILoadAllByExchangeAndPair { var options: any = { fields: { _id: 0 } }; if (limit !== null) { options.limit = limit; - if (count !== 0) + if (count !== 0) options.skip = Math.max(count - limit, 0); } @@ -161,14 +172,10 @@ export class Persister implements ILoadAllByExchangeAndPair { constructor( db: Q.Promise, private _dbName: string, - private _loader: (any) => void, - private _saver: (T) => void) { + private _exchange: Models.Exchange, + private _pair: Models.CurrencyPair, + private _loader: (p: Persistable) => void, + private _saver: (p: Persistable) => void) { this.collection = db.then(db => db.collection(this._dbName)); } -} - -export class BasicPersister extends Persister { - constructor(db: Q.Promise, collectionName: string) { - super(db, collectionName, timeLoader, timeSaver); - } } \ No newline at end of file diff --git a/src/service/position-management.ts b/src/service/position-management.ts index dbe23678f..ea9fffac6 100644 --- a/src/service/position-management.ts +++ b/src/service/position-management.ts @@ -17,12 +17,6 @@ import moment = require("moment"); import Interfaces = require("./interfaces"); import QuotingParameters = require("./quoting-parameters"); -export class RegularFairValuePersister extends Persister.Persister { - constructor(db: Q.Promise) { - super(db, "rfv", Persister.timeLoader, Persister.timeSaver); - } -} - export class PositionManager { private _log: Utils.Logger = Utils.log("tribeca:rfv");