From 567d94597ed117878936c4f385e419c74a36ecac Mon Sep 17 00:00:00 2001 From: root Date: Fri, 8 Apr 2016 17:20:51 +0000 Subject: [PATCH 001/202] Added audio file. --- src/admin/.messages.ts.swp | Bin 0 -> 12288 bytes src/admin/messages.ts | 2 +- src/admin/trades.ts | 9 +++++++-- src/service/.quoting-engine.ts.swp | Bin 0 -> 24576 bytes src/service/quoting-engine.ts | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 src/admin/.messages.ts.swp create mode 100644 src/service/.quoting-engine.ts.swp diff --git a/src/admin/.messages.ts.swp b/src/admin/.messages.ts.swp new file mode 100644 index 0000000000000000000000000000000000000000..bc5360552005ce8db2d687ce3d1f4baade4f8743 GIT binary patch literal 12288 zcmeHN&5ImG6tBeZ#Hc8K96Xfm%FKk>p50ZGFq>V$-E0!#CNXPPFbq=DT{Ba$r@O7H z-Vej#pCAf?co974Nj!V<fg|MUh50#S=SlAg`p|=yZ{DP{;23ZW zI0hU8jseGjW56-s7;p^SG7RYS0C^MM9<&~xv(E$jp7zx}90QI4$ADwNG2j?*3^)cH z1C9a5fMdWh;25|C8DJqHhwdQc(w%S~|Nk%l{{Q-ZLOui}um+q0DDc;PgnS8n3}|2# zSOJa#j{*N4A><$68(;_61TF&Sfpy?<;BTBS_!0O4_#Ws0E5K90Vc_?}gnS2l27CZ) z1DAnEfdjxthY0Bd9bgl<49oz3+(XDOz|X+Dz&YSH;2`kR-GqDrybrtsybW9h`alm@ z0Oo-P@a#8Ho5oJ{Hf@K94;rjQ#vMKbE&KgdK8$AK~dc%;S2^+?$0D~y*6V_ zAk>mAlB?q8OWqesbGbS)!NW5w4w0<&LfV=t8rV?NZ5-%I2v77Qk58;#r}!!P22ZQQMyH5TYZ?)rVME4B-#nzo!o-1lEf zQV}TMF4wS}j!SZX7-^;k^_Xv$6}c(kYZCIPo;7S>#+`{E;8;CF4I8oXQbhvh0oYG& z*zM#4=9jsy(QOgxL7RFSD;J z)iDzAC|VN{J}c}ElOd1wS{6mCXe>3lH!l7liLzn5%6qC!uaMkP+!Rv%Eb_GtuX9h$ zY)zZRI>y<&6j7>X6sZ-|I#ruIHkH1TTfW4Vcw?#?^<|Q!3K9`Z(F&g5g##>$&`~D4 z)N>9K~Cn3 z?NCU9qTNi+DvV$0EE1D6HVF}9+4xQ76!N1j;Dw~$=W@f;X_K0QZ&Rf4SqyJ*xg`RO zPE|p>Y*yn^u=QcvASrep8;A9{O)qq>qB#`BP{ufNWR&^FeGwyTde}qCAS!NBq$`g@ zmHU}HZuX60#qo}(2LeZ%A&QvoTKVg^6blLDlVPPuPhY6@JWtE!?VEgS(C5Y`jC`9G z;*(OgT+ss2Dl^kA%K7P9wHuwWUK;a@l?(rj<8AD855&D@caJq&ymq>557baaFz;sfdWAI<1o6 zHLiV;%m$G_=~o1c&Q%rm$7| { - var template = '
'; + var template = '
'; return { restrict: 'E', diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 3eee203d1..2c3d23eda 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -13,6 +13,7 @@ interface TradesScope extends ng.IScope { exch : Models.Exchange; pair : Models.CurrencyPair; gridOptions : any; + sound: boolean; } class DisplayTrade { @@ -23,13 +24,16 @@ class DisplayTrade { side : string; value : number; - constructor(public trade : Models.Trade) { + constructor($scope : TradesScope, public trade : Models.Trade) { this.tradeId = trade.tradeId; this.side = Models.Side[trade.side]; this.time = (moment.isMoment(trade.time) ? trade.time : moment(trade.time)); this.price = trade.price; this.quantity = trade.quantity; this.value = trade.value; + if ($scope.sound) { + var audio = new Audio('http://antminer/a.mp3');audio.play(); + } } } @@ -55,7 +59,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri ] }; - var addTrade = t => $scope.trade_statuses.push(new DisplayTrade(t)); + var addTrade = t => $scope.trade_statuses.push(new DisplayTrade($scope, t)); var sub = subscriberFactory.getSubscriber($scope, Messaging.Topics.Trades) .registerConnectHandler(() => $scope.trade_statuses.length = 0) @@ -68,6 +72,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri }); $log.info("started trades list"); + setTimeout(function(){$scope.sound = true;},7000); }; var tradeList = () : ng.IDirective => { diff --git a/src/service/.quoting-engine.ts.swp b/src/service/.quoting-engine.ts.swp new file mode 100644 index 0000000000000000000000000000000000000000..8904bdbd1d10268dd8974e9244872b60f9ad4d8a GIT binary patch literal 24576 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 B-B$nr literal 0 HcmV?d00001 diff --git a/src/service/quoting-engine.ts b/src/service/quoting-engine.ts index d36aee89b..c0146dee7 100644 --- a/src/service/quoting-engine.ts +++ b/src/service/quoting-engine.ts @@ -185,4 +185,4 @@ export class QuotingEngine { if (Math.abs(newQ.size - previousQ.size) > 5e-3) return newQ; return Math.abs(newQ.price - previousQ.price) < .009999 ? previousQ : newQ; } -} \ No newline at end of file +} From 531d08aa2ec37a339bb6d8da232db3564b9f7d0f Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 8 Apr 2016 19:23:10 +0200 Subject: [PATCH 002/202] Removed useless files. --- src/admin/.messages.ts.swp | Bin 12288 -> 0 bytes src/service/.quoting-engine.ts.swp | Bin 24576 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/admin/.messages.ts.swp delete mode 100644 src/service/.quoting-engine.ts.swp diff --git a/src/admin/.messages.ts.swp b/src/admin/.messages.ts.swp deleted file mode 100644 index bc5360552005ce8db2d687ce3d1f4baade4f8743..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 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 B-B$nr From 63beeee12ec527c2d5eb1dfc16148b451b5859e0 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 9 Apr 2016 03:35:11 +0200 Subject: [PATCH 003/202] Added bold to Value. --- src/static/index.html | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/static/index.html b/src/static/index.html index 2f739e20b..b42804f37 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -5,9 +5,9 @@ - + - + tribeca [{{ env }}] @@ -93,9 +93,8 @@

{{ baseCurrency }}: {{ basePosition|currency:"B":3 }} ({{ baseHeldPosition|currency:"B":3 }})

-

- Value: {{ value|currency:"B":3 }} -

+

Value: {{ value|currency:"B":3 }} +

@@ -259,22 +258,22 @@

{{ exch_name }}

ng-model="pair.quotingParameters.display.tradeRateSeconds"> - - + From 177cc40504875b33fccd067783db13af20bafcbd Mon Sep 17 00:00:00 2001 From: root Date: Sat, 9 Apr 2016 01:38:44 +0000 Subject: [PATCH 004/202] Added max/min. --- src/service/gateways/coinbase.ts | 6 +++--- src/service/quoting-engine.ts | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/service/gateways/coinbase.ts b/src/service/gateways/coinbase.ts index 4fe80dcd2..468181589 100644 --- a/src/service/gateways/coinbase.ts +++ b/src/service/gateways/coinbase.ts @@ -395,11 +395,11 @@ class CoinbaseMarketDataGateway implements Interfaces.IMarketDataGateway { private _cachedAsks: Models.MarketSide[] = null; private reevalBids = () => { - this._cachedBids = _.map(this._orderBook.bids.store.slice(0, 3), s => (s).value.marketUpdate); + this._cachedBids = _.map(this._orderBook.bids.store.slice(0, 7), s => (s).value.marketUpdate); }; private reevalAsks = () => { - this._cachedAsks = _.map(this._orderBook.asks.store.slice(0, 3), s => (s).value.marketUpdate); + this._cachedAsks = _.map(this._orderBook.asks.store.slice(0, 7), s => (s).value.marketUpdate); }; private onOrderBookChanged = (t: moment.Moment, side: Models.Side, price: number) => { @@ -836,4 +836,4 @@ export class Coinbase extends Interfaces.CombinedGateway { positionGateway, new CoinbaseBaseGateway()); } -}; \ No newline at end of file +}; diff --git a/src/service/quoting-engine.ts b/src/service/quoting-engine.ts index c0146dee7..41a240683 100644 --- a/src/service/quoting-engine.ts +++ b/src/service/quoting-engine.ts @@ -88,6 +88,21 @@ export class QuotingEngine { } } + if (params.mode === Models.QuotingMode.InverseTop) { + for (var fai = 0; fai < Math.min(42, filteredMkt.asks.length); fai++) { + if (filteredMkt.asks[fai].price > unrounded.askPx) { + unrounded.askPx = filteredMkt.asks[fai].price - .01; + break; + } + } + for (var fbi = 0; fbi < Math.min(42, filteredMkt.bids.length); fbi++) { + if (filteredMkt.bids[fbi].price < unrounded.bidPx) { + unrounded.bidPx = filteredMkt.bids[fbi].price + .01; + break; + } + } + } + var tbp = this._targetPosition.latestTargetPosition; if (tbp === null) { this._log.warn("cannot compute a quote since no position report exists!"); From 62fe449dff02e90a325e8b767a92a666463ac86a Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 9 Apr 2016 03:45:00 +0200 Subject: [PATCH 005/202] Added default values. --- src/service/main.ts | 132 ++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/src/service/main.ts b/src/service/main.ts index aebfdcf99..a4e5a554f 100644 --- a/src/service/main.ts +++ b/src/service/main.ts @@ -106,34 +106,34 @@ var messagingLog = Utils.log("tribeca:messaging"); function ParseCurrencyPair(raw: string) : Models.CurrencyPair { var split = raw.split("/"); - if (split.length !== 2) + if (split.length !== 2) throw new Error("Invalid currency pair! Must be in the format of BASE/QUOTE, eg BTC/USD"); - + return new Models.CurrencyPair(Models.Currency[split[0]], Models.Currency[split[1]]); } var pair = ParseCurrencyPair(config.GetString("TradedPair")); var defaultActive : Models.SerializedQuotesActive = new Models.SerializedQuotesActive(false, moment.unix(1)); -var defaultQuotingParameters : Models.QuotingParameters = new Models.QuotingParameters(.3, .05, Models.QuotingMode.Top, - Models.FairValueModel.BBO, 3, .8, false, Models.AutoPositionMode.Off, false, 2.5, 300, .095, 2*.095, .095, 3, .1); +var defaultQuotingParameters : Models.QuotingParameters = new Models.QuotingParameters(1, 1, Models.QuotingMode.InverseTop, + Models.FairValueModel.BBO, 2, 2, true, Models.AutoPositionMode.EwmaBasic, false, 2.5, 84, .095, 2*.095, .095, 3, .1); var backTestSimulationSetup = (inputData : Array, parameters : Backtest.BacktestParameters) => { var timeProvider : Utils.ITimeProvider = new Backtest.BacktestTimeProvider(_.first(inputData).time, _.last(inputData).time); var exchange = Models.Exchange.Null; var gw = new Backtest.BacktestGateway(inputData, parameters.startingBasePosition, parameters.startingQuotePosition, timeProvider); - + var getExch = (orderCache: Broker.OrderStateCache): Interfaces.CombinedGateway => new Backtest.BacktestExchange(gw); - - var getPublisher = (topic: string, persister?: Persister.ILoadAll): Messaging.IPublish => { + + var getPublisher = (topic: string, persister?: Persister.ILoadAll): Messaging.IPublish => { return new Messaging.NullPublisher(); }; - + var getReceiver = (topic: string) : Messaging.IReceive => new Messaging.NullReceiver(); - + var getPersister = (collectionName: string) : Persister.ILoadAll => new Backtest.BacktestPersister(); - + var getRepository = (defValue: T, collectionName: string) : Persister.ILoadLatest => new Backtest.BacktestPersister([defValue]); - + var startingActive : Models.SerializedQuotesActive = new Models.SerializedQuotesActive(true, timeProvider.utcNow()); var startingParameters : Models.QuotingParameters = parameters.quotingParameters; @@ -152,7 +152,7 @@ var backTestSimulationSetup = (inputData : Array { var timeProvider : Utils.ITimeProvider = new Utils.RealTimeProvider(); - + var app = express(); var http_server = http.createServer(app); var io = socket_io(http_server); @@ -167,10 +167,10 @@ var liveTradingSetup = () => { app.use(compression()); app.use(express.static(path.join(__dirname, "admin"))); - + var webport = config.GetNumber("WebClientListenPort"); http_server.listen(webport, () => mainLog.info('Listening to admins on *:', webport)); - + var getExchange = (): Models.Exchange => { var ex = config.GetString("EXCHANGE").toLowerCase(); switch (ex) { @@ -182,9 +182,9 @@ var liveTradingSetup = () => { default: throw new Error("unknown configuration env variable EXCHANGE " + ex); } }; - + var exchange = getExchange(); - + var getExch = (orderCache: Broker.OrderStateCache): Interfaces.CombinedGateway => { switch (exchange) { case Models.Exchange.HitBtc: return (new HitBtc.HitBtc(config, pair)); @@ -195,7 +195,7 @@ var liveTradingSetup = () => { default: throw new Error("no gateway provided for exchange " + exchange); } }; - + var getPublisher = (topic: string, persister?: Persister.ILoadAll): Messaging.IPublish => { var socketIoPublisher = new Messaging.Publisher(topic, io, null, messagingLog.info.bind(messagingLog)); if (persister) @@ -203,21 +203,21 @@ var liveTradingSetup = () => { else return socketIoPublisher; }; - - var getReceiver = (topic: string) : Messaging.IReceive => + + var getReceiver = (topic: string) : Messaging.IReceive => new Messaging.Receiver(topic, io, messagingLog.info.bind(messagingLog)); - + var db = Persister.loadDb(config); - + 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 => + + var getRepository = (defValue: T, collectionName: string) : Persister.ILoadLatest => new Persister.RepositoryPersister(db, defValue, collectionName, exchange, pair, loaderSaver.loader, loaderSaver.saver); return { @@ -257,13 +257,13 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { var tbpPersister = getPersister("tbp"); var tsvPersister = getPersister("tsv"); var marketDataPersister = getPersister(Messaging.Topics.MarketData); - + var activePersister = classes.getRepository(classes.startingActive, Messaging.Topics.ActiveChange); var paramsPersister = classes.getRepository(classes.startingParameters, Messaging.Topics.QuotingParametersChange); - + var exchange = classes.exchange; var completedSuccessfully = Q.defer(); - + Q.all([ orderPersister.loadAll(25000), tradesPersister.loadAll(10000), @@ -279,17 +279,17 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { initParams: Models.QuotingParameters, initActive: Models.SerializedQuotesActive, initRfv: Models.RegularFairValue[]) => { - + _.defaults(initParams, defaultQuotingParameters); _.defaults(initActive, defaultActive); - + var orderCache = new Broker.OrderStateCache(); var timeProvider = classes.timeProvider; var getPublisher = classes.getPublisher; - + var advert = new Models.ProductAdvertisement(exchange, pair, config.GetString("TRIBECA_MODE")); getPublisher(Messaging.Topics.ProductAdvertisement).registerSnapshot(() => [advert]).publish(advert); - + var quotePublisher = getPublisher(Messaging.Topics.Quote); var fvPublisher = getPublisher(Messaging.Topics.FairValue, fairValuePersister); var marketDataPublisher = getPublisher(Messaging.Topics.MarketData, marketDataPersister); @@ -304,47 +304,47 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { var tradeSafetyPublisher = getPublisher(Messaging.Topics.TradeSafetyValue, tsvPersister); var positionPublisher = getPublisher(Messaging.Topics.Position, positionPersister); var connectivity = getPublisher(Messaging.Topics.ExchangeConnectivity); - + var messages = new Messages.MessagesPubisher(timeProvider, messagesPersister, initMsgs, messagesPublisher); messages.publish("start up"); - + var getReceiver = classes.getReceiver; var activeReceiver = getReceiver(Messaging.Topics.ActiveChange); var quotingParametersReceiver = getReceiver(Messaging.Topics.QuotingParametersChange); var submitOrderReceiver = getReceiver(Messaging.Topics.SubmitNewOrder); var cancelOrderReceiver = getReceiver(Messaging.Topics.CancelOrder); var cancelAllOrdersReceiver = getReceiver(Messaging.Topics.CancelAllOrders); - + var gateway = classes.getExch(orderCache); - + if (!_.some(gateway.base.supportedCurrencyPairs, p => p.base === pair.base && p.quote === pair.quote)) throw new Error("Unsupported currency pair!. Please check that gateway " + gateway.base.name() + " supports the value specified in TradedPair config value"); - + var broker = new Broker.ExchangeBroker(pair, gateway.md, gateway.base, gateway.oe, connectivity); var orderBroker = new Broker.OrderBroker(timeProvider, broker, gateway.oe, orderPersister, tradesPersister, orderStatusPublisher, tradePublisher, submitOrderReceiver, cancelOrderReceiver, cancelAllOrdersReceiver, messages, orderCache, initOrders, initTrades); var marketDataBroker = new Broker.MarketDataBroker(gateway.md, marketDataPublisher, marketDataPersister, messages); var positionBroker = new Broker.PositionBroker(timeProvider, broker, gateway.pg, positionPublisher, positionPersister, marketDataBroker); - + var paramsRepo = new QuotingParameters.QuotingParametersRepository(quotingParametersPublisher, quotingParametersReceiver, initParams); paramsRepo.NewParameters.on(() => paramsPersister.persist(paramsRepo.latest)); - + var safetyCalculator = new Safety.SafetyCalculator(timeProvider, paramsRepo, orderBroker, paramsRepo, tradeSafetyPublisher, tsvPersister); - + var startQuoting = (timeProvider.utcNow().diff(initActive.time, 'minutes') < 3 && initActive.active); var active = new Active.ActiveRepository(startQuoting, broker, activePublisher, activeReceiver); - + var quoter = new Quoter.Quoter(orderBroker, broker); var filtration = new MarketFiltration.MarketFiltration(quoter, marketDataBroker); var fvEngine = new FairValue.FairValueEngine(timeProvider, filtration, paramsRepo, fvPublisher, fairValuePersister); var ewma = new Statistics.ObservableEWMACalculator(timeProvider, fvEngine, initParams.quotingEwma); - + var rfvValues = _.map(initRfv, (r: Models.RegularFairValue) => r.value); var shortEwma = new Statistics.EwmaStatisticCalculator(initParams.shortEwma); shortEwma.initialize(rfvValues); var longEwma = new Statistics.EwmaStatisticCalculator(initParams.longEwma); longEwma.initialize(rfvValues); - + var registry = new QuotingStyleRegistry.QuotingStyleRegistry([ new MidMarket.MidMarketQuoteStyle(), new TopJoin.InverseJoinQuoteStyle(), @@ -352,16 +352,16 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { new TopJoin.JoinQuoteStyle(), new TopJoin.TopOfTheMarketQuoteStyle(), ]); - + var positionMgr = new PositionManagement.PositionManager(timeProvider, rfvPersister, fvEngine, initRfv, shortEwma, longEwma); var tbp = new PositionManagement.TargetBasePositionManager(timeProvider, positionMgr, paramsRepo, positionBroker, targetBasePositionPublisher, tbpPersister); var quotingEngine = new QuotingEngine.QuotingEngine(registry, timeProvider, filtration, fvEngine, paramsRepo, quotePublisher, orderBroker, positionBroker, ewma, tbp, safetyCalculator); var quoteSender = new QuoteSender.QuoteSender(timeProvider, quotingEngine, quoteStatusPublisher, quoter, active, positionBroker, fvEngine, marketDataBroker, broker); - + var marketTradeBroker = new MarketTrades.MarketTradeBroker(gateway.md, marketTradePublisher, marketDataBroker, quotingEngine, broker, mktTradePersister, initMktTrades); - + if (config.inBacktestMode) { var t = Utils.date(); console.log("starting backtest"); @@ -373,21 +373,21 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { completedSuccessfully.reject(err); return completedSuccessfully.promise; } - + var results = [paramsRepo.latest, positionBroker.latestReport, { trades: orderBroker._trades.map(t => [t.time.valueOf(), t.price, t.quantity, t.side]), volume: orderBroker._trades.reduce((p, c) => p + c.quantity, 0) }]; console.log("sending back results, took: ", Utils.date().diff(t, "seconds")); - - request({url: serverUrl+"/result", - method: 'POST', + + request({url: serverUrl+"/result", + method: 'POST', json: results}, (err, resp, body) => { }); - + completedSuccessfully.resolve(true); return completedSuccessfully.promise; } - + exitingEvent = () => { var a = new Models.SerializedQuotesActive(active.savedQuotingMode, timeProvider.utcNow()); mainLog.info("persisting active to", a.active); @@ -405,7 +405,7 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { }, moment.duration(1000)); return completedSuccessfully.promise; }; - + // event looped blocked timer var start = process.hrtime(); var interval = 100; @@ -417,7 +417,7 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { mainLog.info("Event looped blocked for " + Utils.roundFloat(n) + "ms"); start = process.hrtime(); }, interval).unref(); - + }).done(); return completedSuccessfully.promise; @@ -426,59 +426,59 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { var harness = () : Q.Promise => { if (config.inBacktestMode) { console.log("enter backtest mode"); - + var getFromBacktestServer = (ep: string) : Q.Promise => { var d = Q.defer(); - request.get(serverUrl+"/"+ep, (err, resp, body) => { + request.get(serverUrl+"/"+ep, (err, resp, body) => { if (err) d.reject(err); else d.resolve(body); }); return d.promise; }; - + var inputDataPromise = getFromBacktestServer("inputData").then(body => { var inp : Array = (typeof body ==="string") ? eval(body) : body; - + for (var i = 0; i < inp.length; i++) { var d = inp[i]; d.time = moment(d.time); } - + return inp; }); - + var nextParameters = () : Q.Promise => getFromBacktestServer("nextParameters").then(body => { var p = (typeof body ==="string") ? JSON.parse(body) : body; console.log("Recv'd parameters", util.inspect(p)); return (typeof p === "string") ? null : p; }); - + var promiseWhile = (body : () => Q.Promise) => { var done = Q.defer(); - + var loop = () => { body().then(possibleResult => { if (!possibleResult) return done.resolve(null); else Q.when(possibleResult, loop, done.reject); }); }; - + Q.nextTick(loop); return done.promise; }; - + var runLoop = (inputMarketData : Array) : Q.Promise => { var singleRun = () => { var runWithParameters = (p : Backtest.BacktestParameters) => { return p !== null ? runTradingSystem(backTestSimulationSetup(inputMarketData, p)) : false; }; - + return nextParameters().then(runWithParameters); }; - + return promiseWhile(singleRun); }; - + return inputDataPromise.then(runLoop); } else { From 908e1144b104063a0bf74e26acde5ff4ad050cfc Mon Sep 17 00:00:00 2001 From: root Date: Sat, 9 Apr 2016 01:59:59 +0000 Subject: [PATCH 006/202] Removed useless block. --- src/admin/messages.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/messages.ts b/src/admin/messages.ts index ba1974fbe..9caf61bb4 100644 --- a/src/admin/messages.ts +++ b/src/admin/messages.ts @@ -63,7 +63,7 @@ export var messagesDirective = "messagesDirective"; angular .module(messagesDirective, ['ui.bootstrap', 'ui.grid', Shared.sharedDirectives]) .directive("messagesGrid", () => { - var template = '
'; + var template = '
'; return { restrict: 'E', From 14799a7a7e39bbabecabc6cd84b8d66bfbb4a518 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 9 Apr 2016 02:02:13 +0000 Subject: [PATCH 007/202] Added moar mktN. --- src/service/gateways/coinbase.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/gateways/coinbase.ts b/src/service/gateways/coinbase.ts index 468181589..176badbc0 100644 --- a/src/service/gateways/coinbase.ts +++ b/src/service/gateways/coinbase.ts @@ -395,11 +395,11 @@ class CoinbaseMarketDataGateway implements Interfaces.IMarketDataGateway { private _cachedAsks: Models.MarketSide[] = null; private reevalBids = () => { - this._cachedBids = _.map(this._orderBook.bids.store.slice(0, 7), s => (s).value.marketUpdate); + this._cachedBids = _.map(this._orderBook.bids.store.slice(0, 9), s => (s).value.marketUpdate); }; private reevalAsks = () => { - this._cachedAsks = _.map(this._orderBook.asks.store.slice(0, 7), s => (s).value.marketUpdate); + this._cachedAsks = _.map(this._orderBook.asks.store.slice(0, 9), s => (s).value.marketUpdate); }; private onOrderBookChanged = (t: moment.Moment, side: Models.Side, price: number) => { From f6602537ac1e52230bfa7a09769a19d4cb996511 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 9 Apr 2016 04:15:00 +0200 Subject: [PATCH 008/202] Fixed width of val column. --- src/admin/trades.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 2c3d23eda..9a00ce7da 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -55,7 +55,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri {width: 55, field:'price', displayName:'px', cellFilter: 'currency'}, {width: 50, field:'quantity', displayName:'qty'}, {width: 35, field:'side', displayName:'side'}, - {width: 50, field:'value', displayName:'val', cellFilter: 'currency:"$":3'} + {width: 70, field:'value', displayName:'val', cellFilter: 'currency:"$":3'} ] }; From d205e64d71a9bb2350bb8d5bf06ec1ff92fabe50 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 9 Apr 2016 14:59:17 +0200 Subject: [PATCH 009/202] Added Top to min/max. --- src/service/quoting-engine.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/service/quoting-engine.ts b/src/service/quoting-engine.ts index 41a240683..02a231ea5 100644 --- a/src/service/quoting-engine.ts +++ b/src/service/quoting-engine.ts @@ -67,14 +67,14 @@ export class QuotingEngine { _quotePublisher.registerSnapshot(() => this.latestQuote === null ? [] : [this.latestQuote]); _targetPosition.NewTargetPosition.on(recalcWithoutInputTime); _safeties.NewValue.on(recalcWithoutInputTime); - + _timeProvider.setInterval(recalcWithoutInputTime, moment.duration(1, "seconds")); } private computeQuote(filteredMkt: Models.Market, fv: Models.FairValue) { var params = this._qlParamRepo.latest; var unrounded = this._registry.Get(params.mode).GenerateQuote(filteredMkt, fv, params); - + if (unrounded === null) return null; @@ -88,7 +88,7 @@ export class QuotingEngine { } } - if (params.mode === Models.QuotingMode.InverseTop) { + if (params.mode === Models.QuotingMode.Top || params.mode === Models.QuotingMode.InverseTop) { for (var fai = 0; fai < Math.min(42, filteredMkt.asks.length); fai++) { if (filteredMkt.asks[fai].price > unrounded.askPx) { unrounded.askPx = filteredMkt.asks[fai].price - .01; @@ -109,30 +109,30 @@ export class QuotingEngine { return null; } var targetBasePosition = tbp.data; - + var latestPosition = this._positionBroker.latestReport; var totalBasePosition = latestPosition.baseAmount + latestPosition.baseHeldAmount; - + if (totalBasePosition < targetBasePosition - params.positionDivergence) { unrounded.askPx = null; unrounded.askSz = null; if (params.aggressivePositionRebalancing) unrounded.bidSz = Math.min(params.aprMultiplier*params.size, targetBasePosition - totalBasePosition); } - + if (totalBasePosition > targetBasePosition + params.positionDivergence) { unrounded.bidPx = null; unrounded.bidSz = null; if (params.aggressivePositionRebalancing) unrounded.askSz = Math.min(params.aprMultiplier*params.size, totalBasePosition - targetBasePosition); } - + var safety = this._safeties.latest; if (safety === null) { this._log.warn("cannot compute a quote since trade safety is not yet computed!"); return null; } - + if (safety.sell > params.tradesPerMinute) { unrounded.askPx = null; unrounded.askSz = null; @@ -141,22 +141,22 @@ export class QuotingEngine { unrounded.bidPx = null; unrounded.bidSz = null; } - + if (unrounded.bidPx !== null) { unrounded.bidPx = Utils.roundFloat(unrounded.bidPx); unrounded.bidPx = Math.max(0, unrounded.bidPx); } - + if (unrounded.askPx !== null) { unrounded.askPx = Utils.roundFloat(unrounded.askPx); unrounded.askPx = Math.max(unrounded.bidPx + .01, unrounded.askPx); } - + if (unrounded.askSz !== null) { unrounded.askSz = Utils.roundFloat(unrounded.askSz); unrounded.askSz = Math.max(0.01, unrounded.askSz); } - + if (unrounded.bidSz !== null) { unrounded.bidSz = Utils.roundFloat(unrounded.bidSz); unrounded.bidSz = Math.max(0.01, unrounded.bidSz); From b3cffc9cdfda35148386b9cfc5a37492d759beaa Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 9 Apr 2016 15:39:52 +0200 Subject: [PATCH 010/202] Added displays. --- src/admin/market-quoting.ts | 4 ++++ src/admin/position.ts | 2 ++ src/common/models.ts | 1 + src/service/broker.ts | 17 +++++++++-------- src/static/index.html | 2 +- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/admin/market-quoting.ts b/src/admin/market-quoting.ts index 0d70960e4..641c6e1eb 100644 --- a/src/admin/market-quoting.ts +++ b/src/admin/market-quoting.ts @@ -14,6 +14,7 @@ class Level { bidSize: number; askPrice: number; askSize: number; + diffWidth: number; bidClass: string; askClass: string; @@ -86,8 +87,11 @@ var MarketQuotingController = ($scope: MarketQuotingScope, $scope.levels[i] = new Level(); $scope.levels[i].bidPrice = update.bids[i].price; $scope.levels[i].bidSize = update.bids[i].size; + $scope.levels[i].diffWidth = (i==0) + ? $scope.levels[i].askPrice - $scope.levels[i].bidPrice : 0; } + updateQuoteClass(); }; diff --git a/src/admin/position.ts b/src/admin/position.ts index 75e59dfb6..f8d8b9f69 100644 --- a/src/admin/position.ts +++ b/src/admin/position.ts @@ -20,6 +20,7 @@ interface PositionScope extends ng.IScope { baseHeldPosition : number; quoteHeldPosition : number; value : number; + valueFiat : number; } var PositionController = ($scope : PositionScope, $log : ng.ILogService, subscriberFactory : Shared.SubscriberFactory) => { @@ -41,6 +42,7 @@ var PositionController = ($scope : PositionScope, $log : ng.ILogService, subscri $scope.baseHeldPosition = position.baseHeldAmount; $scope.quoteHeldPosition = position.quoteHeldAmount; $scope.value = position.value; + $scope.valueFiat = position.valueFiat; }; var positionSubscriber = subscriberFactory.getSubscriber($scope, Messaging.Topics.Position) diff --git a/src/common/models.ts b/src/common/models.ts index 0a97faa24..0196cb3f3 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -262,6 +262,7 @@ export class PositionReport { public baseHeldAmount: number, public quoteHeldAmount: number, public value: number, + public valueFiat: number, public quoteValue: number, public pair: CurrencyPair, public exchange: Exchange, diff --git a/src/service/broker.ts b/src/service/broker.ts index c36575d7a..762d70695 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -56,7 +56,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { if (this._oeGateway.supportsCancelAllOpenOrders()) { return this._oeGateway.cancelAllOpenOrders(); } - + var deferred = Q.defer(); var lateCancels : {[id: string] : boolean} = {}; @@ -311,16 +311,16 @@ export class OrderBroker implements Interfaces.IOrderBroker { _cancelOrderReciever.registerReceiver(o => { this._log.info("got new cancel req", o); try { - this.cancelOrder(new Models.OrderCancel(o.orderId, o.exchange, _timeProvider.utcNow())); + this.cancelOrder(new Models.OrderCancel(o.orderId, o.exchange, _timeProvider.utcNow())); } catch (e) { this._log.error(e, "unhandled exception while submitting order", o); } }); - + _cancelAllOrdersReciever.registerReceiver(o => { this._log.info("handling cancel all orders request"); this.cancelOpenOrders() - .then(x => this._log.info("cancelled all ", x, " open orders"), + .then(x => this._log.info("cancelled all ", x, " open orders"), e => this._log.error(e, "error when cancelling all orders!")); }); @@ -369,12 +369,13 @@ export class PositionBroker implements Interfaces.IPositionBroker { var quoteAmount = quotePosition.amount; var mid = (this._mdBroker.currentBook.bids[0].price + this._mdBroker.currentBook.asks[0].price) / 2.0; var baseValue = baseAmount + quoteAmount / mid + basePosition.heldAmount + quotePosition.heldAmount / mid; + var valueFiat = baseValue * mid; var quoteValue = baseAmount * mid + quoteAmount + basePosition.heldAmount * mid + quotePosition.heldAmount; var positionReport = new Models.PositionReport(baseAmount, quoteAmount, basePosition.heldAmount, - quotePosition.heldAmount, baseValue, quoteValue, this._base.pair, this._base.exchange(), this._timeProvider.utcNow()); + quotePosition.heldAmount, baseValue, valueFiat, quoteValue, this._base.pair, this._base.exchange(), this._timeProvider.utcNow()); - if (this._report !== null && - Math.abs(positionReport.value - this._report.value) < 2e-2 && + if (this._report !== null && + Math.abs(positionReport.value - this._report.value) < 2e-2 && Math.abs(baseAmount - this._report.baseAmount) < 2e-2 && Math.abs(positionReport.baseHeldAmount - this._report.baseHeldAmount) < 2e-2 && Math.abs(positionReport.quoteHeldAmount - this._report.quoteHeldAmount) < 2e-2) @@ -420,7 +421,7 @@ export class ExchangeBroker implements Interfaces.IBroker { public get pair() { return this._pair; } - + public get supportedCurrencyPairs() : Models.CurrencyPair[] { return this._baseGateway.supportedCurrencyPairs; } diff --git a/src/static/index.html b/src/static/index.html index b42804f37..731deff85 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -49,7 +49,7 @@ mkt{{ $index }} {{ level.bidSize|number:2 }} {{ level.bidPrice|number:2 }} - + {{ level.diffWidth|number:2 }} {{ level.askPrice|number:2 }} {{ level.askSize|number:2 }} From a3ac6fb6ce886feadf6bdce3f6495b1ddab10f36 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 9 Apr 2016 15:43:07 +0200 Subject: [PATCH 011/202] Added fiat value. --- src/static/index.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/static/index.html b/src/static/index.html index 731deff85..e581803a8 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -93,7 +93,11 @@

{{ baseCurrency }}: {{ basePosition|currency:"B":3 }} ({{ baseHeldPosition|currency:"B":3 }})

-

Value: {{ value|currency:"B":3 }} +

+ Value: {{ value|currency:"B":3 }} +

+

+ Value: {{ valueFiat|currency:undefined:3 }}

From e5147644896cfc195ef804952a3170bd329fa3fa Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 9 Apr 2016 15:45:24 +0200 Subject: [PATCH 012/202] Updated fiat value. --- src/static/index.html | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/static/index.html b/src/static/index.html index e581803a8..b250b3461 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -94,10 +94,8 @@

{{ baseCurrency }}: {{ basePosition|currency:"B":3 }} ({{ baseHeldPosition|currency:"B":3 }})

- Value: {{ value|currency:"B":3 }} -

-

- Value: {{ valueFiat|currency:undefined:3 }} + Value: {{ value|currency:"B":3 }}
+ {{ valueFiat|currency:undefined:3 }}

From e814d29e894f4e93f5a772f391f2ed5cc1825cbc Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 9 Apr 2016 15:49:33 +0200 Subject: [PATCH 013/202] Updated fiat value. --- src/static/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/index.html b/src/static/index.html index b250b3461..62be6aa66 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -95,7 +95,7 @@

Value: {{ value|currency:"B":3 }}
- {{ valueFiat|currency:undefined:3 }} + {{ valueFiat|currency:undefined:2 }}

From b2dd025c51c49e6aa95500bbb31a005b82f20e62 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 9 Apr 2016 16:12:31 +0200 Subject: [PATCH 014/202] Fixed qty column. --- src/admin/trades.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 9a00ce7da..bf4f7a932 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -53,7 +53,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri sortingAlgorithm: (a: moment.Moment, b: moment.Moment) => a.diff(b), sort: { direction: uiGridConstants.DESC, priority: 1} }, {width: 55, field:'price', displayName:'px', cellFilter: 'currency'}, - {width: 50, field:'quantity', displayName:'qty'}, + {width: 70, field:'quantity', displayName:'qty'}, {width: 35, field:'side', displayName:'side'}, {width: 70, field:'value', displayName:'val', cellFilter: 'currency:"$":3'} ] From aa9c894550cc8e21e0508231f66cfc6782917f40 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 9 Apr 2016 20:51:42 +0200 Subject: [PATCH 015/202] Added moar digits. --- src/static/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/index.html b/src/static/index.html index 62be6aa66..5a0dfacf1 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -94,7 +94,7 @@

{{ baseCurrency }}: {{ basePosition|currency:"B":3 }} ({{ baseHeldPosition|currency:"B":3 }})

- Value: {{ value|currency:"B":3 }}
+ Value: {{ value|currency:"B":5 }}
{{ valueFiat|currency:undefined:2 }}

From 6ea6ecb99809ed74a3929cea5b85b9ec1c83e5f1 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 10 Apr 2016 14:05:01 +0200 Subject: [PATCH 016/202] Added width of qBid/qAsk. --- src/admin/market-quoting.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/admin/market-quoting.ts b/src/admin/market-quoting.ts index 641c6e1eb..2f47c26fe 100644 --- a/src/admin/market-quoting.ts +++ b/src/admin/market-quoting.ts @@ -87,8 +87,11 @@ var MarketQuotingController = ($scope: MarketQuotingScope, $scope.levels[i] = new Level(); $scope.levels[i].bidPrice = update.bids[i].price; $scope.levels[i].bidSize = update.bids[i].size; - $scope.levels[i].diffWidth = (i==0) - ? $scope.levels[i].askPrice - $scope.levels[i].bidPrice : 0; + $scope.levels[i].diffWidth = i==0 + ? $scope.levels[i].askPrice - $scope.levels[i].bidPrice : ( + (i==1 && $scope.qBidPx && $scope.qAskPx) + ? $scope.qBidPx - $scope.qAskPx : 0 + ); } From 7f03f93fe5211920203bb29cf1ba0d632a281d6d Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 10 Apr 2016 14:09:57 +0200 Subject: [PATCH 017/202] Fixed morning typo. --- src/admin/market-quoting.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/market-quoting.ts b/src/admin/market-quoting.ts index 2f47c26fe..97da7d4df 100644 --- a/src/admin/market-quoting.ts +++ b/src/admin/market-quoting.ts @@ -90,7 +90,7 @@ var MarketQuotingController = ($scope: MarketQuotingScope, $scope.levels[i].diffWidth = i==0 ? $scope.levels[i].askPrice - $scope.levels[i].bidPrice : ( (i==1 && $scope.qBidPx && $scope.qAskPx) - ? $scope.qBidPx - $scope.qAskPx : 0 + ? $scope.qAskPx - $scope.qBidPx : 0 ); } From bb0ed27f75189a3a11acf72480becdd026bd3440 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 10 Apr 2016 19:36:20 +0200 Subject: [PATCH 018/202] Added dummy quote style. --- src/common/models.ts | 2 +- src/service/main.ts | 3 +- src/service/quoting-engine.ts | 4 +-- src/service/quoting-styles/top-join.ts | 39 +++++++++++++++++++++++--- 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/common/models.ts b/src/common/models.ts index 0196cb3f3..1ceef5044 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -325,7 +325,7 @@ export function currencyPairEqual(a: CurrencyPair, b: CurrencyPair): boolean { return a.base === b.base && a.quote === b.quote; } -export enum QuotingMode { Top, Mid, Join, InverseJoin, InverseTop } +export enum QuotingMode { Top, Mid, Join, InverseJoin, InverseTop, PingPong } export enum FairValueModel { BBO, wBBO } export enum AutoPositionMode { Off, EwmaBasic } diff --git a/src/service/main.ts b/src/service/main.ts index a4e5a554f..32cdafadc 100644 --- a/src/service/main.ts +++ b/src/service/main.ts @@ -114,7 +114,7 @@ function ParseCurrencyPair(raw: string) : Models.CurrencyPair { var pair = ParseCurrencyPair(config.GetString("TradedPair")); var defaultActive : Models.SerializedQuotesActive = new Models.SerializedQuotesActive(false, moment.unix(1)); -var defaultQuotingParameters : Models.QuotingParameters = new Models.QuotingParameters(1, 1, Models.QuotingMode.InverseTop, +var defaultQuotingParameters : Models.QuotingParameters = new Models.QuotingParameters(1, 1, Models.QuotingMode.Top, Models.FairValueModel.BBO, 2, 2, true, Models.AutoPositionMode.EwmaBasic, false, 2.5, 84, .095, 2*.095, .095, 3, .1); var backTestSimulationSetup = (inputData : Array, parameters : Backtest.BacktestParameters) => { @@ -351,6 +351,7 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { new TopJoin.InverseTopOfTheMarketQuoteStyle(), new TopJoin.JoinQuoteStyle(), new TopJoin.TopOfTheMarketQuoteStyle(), + new TopJoin.PingPongQuoteStyle(), ]); var positionMgr = new PositionManagement.PositionManager(timeProvider, rfvPersister, fvEngine, initRfv, shortEwma, longEwma); diff --git a/src/service/quoting-engine.ts b/src/service/quoting-engine.ts index 02a231ea5..98b32c5cf 100644 --- a/src/service/quoting-engine.ts +++ b/src/service/quoting-engine.ts @@ -88,7 +88,7 @@ export class QuotingEngine { } } - if (params.mode === Models.QuotingMode.Top || params.mode === Models.QuotingMode.InverseTop) { + // if (params.mode === Models.QuotingMode.Top || params.mode === Models.QuotingMode.InverseTop) { for (var fai = 0; fai < Math.min(42, filteredMkt.asks.length); fai++) { if (filteredMkt.asks[fai].price > unrounded.askPx) { unrounded.askPx = filteredMkt.asks[fai].price - .01; @@ -101,7 +101,7 @@ export class QuotingEngine { break; } } - } + // } var tbp = this._targetPosition.latestTargetPosition; if (tbp === null) { diff --git a/src/service/quoting-styles/top-join.ts b/src/service/quoting-styles/top-join.ts index 1ca42e51f..32c3dd543 100644 --- a/src/service/quoting-styles/top-join.ts +++ b/src/service/quoting-styles/top-join.ts @@ -5,7 +5,7 @@ import Models = require("../../common/models"); export class TopOfTheMarketQuoteStyle implements StyleHelpers.QuoteStyle { Mode = Models.QuotingMode.Top; - + GenerateQuote = (market: Models.Market, fv: Models.FairValue, params: Models.QuotingParameters) : StyleHelpers.GeneratedQuote => { return computeTopJoinQuote(market, fv, params); }; @@ -13,7 +13,7 @@ export class TopOfTheMarketQuoteStyle implements StyleHelpers.QuoteStyle { export class InverseTopOfTheMarketQuoteStyle implements StyleHelpers.QuoteStyle { Mode = Models.QuotingMode.InverseTop; - + GenerateQuote = (market: Models.Market, fv: Models.FairValue, params: Models.QuotingParameters) : StyleHelpers.GeneratedQuote => { return computeInverseJoinQuote(market, fv, params); }; @@ -21,15 +21,23 @@ export class InverseTopOfTheMarketQuoteStyle implements StyleHelpers.QuoteStyle export class InverseJoinQuoteStyle implements StyleHelpers.QuoteStyle { Mode = Models.QuotingMode.InverseJoin; - + GenerateQuote = (market: Models.Market, fv: Models.FairValue, params: Models.QuotingParameters) : StyleHelpers.GeneratedQuote => { return computeInverseJoinQuote(market, fv, params); }; } +export class PingPongQuoteStyle implements StyleHelpers.QuoteStyle { + Mode = Models.QuotingMode.PingPong; + + GenerateQuote = (market: Models.Market, fv: Models.FairValue, params: Models.QuotingParameters) : StyleHelpers.GeneratedQuote => { + return computePingPongQuote(market, fv, params); + }; +} + export class JoinQuoteStyle implements StyleHelpers.QuoteStyle { Mode = Models.QuotingMode.Join; - + GenerateQuote = (market: Models.Market, fv: Models.FairValue, params: Models.QuotingParameters) : StyleHelpers.GeneratedQuote => { return computeTopJoinQuote(market, fv, params); }; @@ -92,5 +100,28 @@ function computeInverseJoinQuote(filteredMkt: Models.Market, fv: Models.FairValu genQt.bidSz = params.size; genQt.askSz = params.size; + return genQt; +} + +function computePingPongQuote(filteredMkt: Models.Market, fv: Models.FairValue, params: Models.QuotingParameters) { + var genQt = getQuoteAtTopOfMarket(filteredMkt, params); + + if (params.mode === Models.QuotingMode.Top && genQt.bidSz > .2) { + genQt.bidPx += .01; + } + + var minBid = fv.price - params.width / 2.0; + genQt.bidPx = Math.min(minBid, genQt.bidPx); + + if (params.mode === Models.QuotingMode.Top && genQt.askSz > .2) { + genQt.askPx -= .01; + } + + var minAsk = fv.price + params.width / 2.0; + genQt.askPx = Math.max(minAsk, genQt.askPx); + + genQt.bidSz = params.size; + genQt.askSz = params.size; + return genQt; } \ No newline at end of file From e57f9082b62a20c9fe024200296bab3f1ed013df Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 10 Apr 2016 20:22:54 +0200 Subject: [PATCH 019/202] Fixed style. --- src/service/quoting-styles/top-join.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/quoting-styles/top-join.ts b/src/service/quoting-styles/top-join.ts index 32c3dd543..7ef10bad7 100644 --- a/src/service/quoting-styles/top-join.ts +++ b/src/service/quoting-styles/top-join.ts @@ -106,14 +106,14 @@ function computeInverseJoinQuote(filteredMkt: Models.Market, fv: Models.FairValu function computePingPongQuote(filteredMkt: Models.Market, fv: Models.FairValue, params: Models.QuotingParameters) { var genQt = getQuoteAtTopOfMarket(filteredMkt, params); - if (params.mode === Models.QuotingMode.Top && genQt.bidSz > .2) { + if (params.mode === Models.QuotingMode.PingPong && genQt.bidSz > .2) { genQt.bidPx += .01; } var minBid = fv.price - params.width / 2.0; genQt.bidPx = Math.min(minBid, genQt.bidPx); - if (params.mode === Models.QuotingMode.Top && genQt.askSz > .2) { + if (params.mode === Models.QuotingMode.PingPong && genQt.askSz > .2) { genQt.askPx -= .01; } From 0712509edd5098f5ecf2de19ce5e47f3fc9beedb Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 00:54:42 +0200 Subject: [PATCH 020/202] Added PingPong display. --- src/admin/trade-safety.ts | 6 +++++- src/common/models.ts | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/admin/trade-safety.ts b/src/admin/trade-safety.ts index a105bac3c..03d3f0bc4 100644 --- a/src/admin/trade-safety.ts +++ b/src/admin/trade-safety.ts @@ -24,12 +24,16 @@ var TradeSafetyController = ($scope : TradeSafetyScope, $log : ng.ILogService, s $scope.tradeSafetyValue = value.combined; $scope.buySafety = value.buy; $scope.sellSafety = value.sell; + $scope.buySizeSafety = value.buyS; + $scope.sellSizeSafety = value.sellS; }; var clear = () => { $scope.tradeSafetyValue = null; $scope.buySafety = null; $scope.sellSafety = null; + $scope.buySizeSafety = null; + $scope.sellSizeSafety = null; }; var subscriber = subscriberFactory.getSubscriber($scope, Messaging.Topics.TradeSafetyValue) @@ -49,7 +53,7 @@ export var tradeSafetyDirective = "tradeSafetyDirective"; angular .module(tradeSafetyDirective, ['sharedDirectives']) .directive("tradeSafety", () => { - var template = 'BuyTS: {{ buySafety|number:2 }}, SellTS: {{ sellSafety|number:2 }}, TotalTS: {{ tradeSafetyValue|number:2 }}'; + var template = 'BuyLT: {{ buySizeSafety|number:2 }}, SellLT: {{ sellSizeSafety|number:2 }}, BuyTS: {{ buySafety|number:2 }}, SellTS: {{ sellSafety|number:2 }}, TotalTS: {{ tradeSafetyValue|number:2 }}'; return { restrict: 'E', diff --git a/src/common/models.ts b/src/common/models.ts index 7a35af170..eb735b0ff 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -382,6 +382,8 @@ export class RegularFairValue { export class TradeSafety { constructor(public buy: number, public sell: number, + public buyS: number, + public sellS: number, public combined: number, public time: moment.Moment) {} } From c73a758613dff7a83a3d19f96afc220f7d8cb02d Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 01:31:43 +0200 Subject: [PATCH 021/202] Added PingPong calc. --- src/service/safety.ts | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index 0d19ba3c8..442c2f42e 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -33,6 +33,8 @@ export class SafetyCalculator { private _buys: Models.Trade[] = []; private _sells: Models.Trade[] = []; + private _buysS: Models.Trade[] = []; + private _sellsS: Models.Trade[] = []; constructor( private _timeProvider: Utils.ITimeProvider, @@ -45,7 +47,7 @@ export class SafetyCalculator { _repo.NewParameters.on(_ => this.computeQtyLimit()); _qlParams.NewParameters.on(_ => this.computeQtyLimit()); _broker.Trade.on(this.onTrade); - + _timeProvider.setInterval(this.computeQtyLimit, moment.duration(1, "seconds")); } @@ -55,9 +57,11 @@ export class SafetyCalculator { if (u.side === Models.Side.Ask) { this._sells.push(u); + this._sellsS.unshift(u); } else if (u.side === Models.Side.Bid) { this._buys.push(u); + this._buysS.unshift(u); } this.computeQtyLimit(); @@ -81,6 +85,27 @@ export class SafetyCalculator { this._buys = orderTrades(this._buys, -1); this._sells = orderTrades(this._sells, 1); + var buyS = sellS = buySq = sellSq = 0; + for (var bSi = 0; bSi < this._buysS.length; bSi++) { + if (buySq>settings.width) break; + buyS = this._buysS[bSi].price / this._buysS[bSi].quantity; + buySq += this._buysS[bSi].quantity; + } + if (bSi) { + buyS /= bSi; + this._buysS.slice(0,bSi); + } + + for (var sSi = 0; sSi < this._sellsS.length; sSi++) { + if (sellSq>settings.width) break; + sellS = this._sellsS[sSi].price / this._sellsS[sSi].quantity; + sellSq += this._sellsS[sSi].quantity; + } + if (sSi) { + sellS /= sSi; + this._sellsS.slice(0,sSi); + } + // don't count good trades against safety while (_.size(this._buys) > 0 && _.size(this._sells) > 0) { var sell = _.last(this._sells); @@ -104,6 +129,6 @@ export class SafetyCalculator { var computeSafety = (t: Models.Trade[]) => t.reduce((sum, t) => sum + t.quantity, 0) / this._qlParams.latest.size; this.latest = new Models.TradeSafety(computeSafety(this._buys), computeSafety(this._sells), - computeSafety(this._buys.concat(this._sells)), this._timeProvider.utcNow()); + buyS, sellS, computeSafety(this._buys.concat(this._sells)), this._timeProvider.utcNow()); }; } \ No newline at end of file From 9cc64c0542511f06e13603f83f5900319ff714b9 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 01:35:11 +0200 Subject: [PATCH 022/202] Fixed ts. --- src/service/safety.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index 442c2f42e..84024e44f 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -85,7 +85,10 @@ export class SafetyCalculator { this._buys = orderTrades(this._buys, -1); this._sells = orderTrades(this._sells, 1); - var buyS = sellS = buySq = sellSq = 0; + var buyS = 0; + var sellS = 0; + var buySq = 0; + var sellSq = 0; for (var bSi = 0; bSi < this._buysS.length; bSi++) { if (buySq>settings.width) break; buyS = this._buysS[bSi].price / this._buysS[bSi].quantity; From 89dd479bf137b58566c4077cbd2261c6b1f7bca4 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 01:37:06 +0200 Subject: [PATCH 023/202] Fixed ts. --- src/admin/trade-safety.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/admin/trade-safety.ts b/src/admin/trade-safety.ts index 03d3f0bc4..92284a611 100644 --- a/src/admin/trade-safety.ts +++ b/src/admin/trade-safety.ts @@ -14,6 +14,8 @@ import Shared = require("./shared_directives"); interface TradeSafetyScope extends ng.IScope { buySafety: number; sellSafety: number; + buySizeSafety: number; + sellSizeSafety: number; tradeSafetyValue : number; } From 06d17ebee868b8298db215e730d0b68a5ff340b4 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 01:49:21 +0200 Subject: [PATCH 024/202] Fixed prev trades. --- src/service/safety.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index 84024e44f..d3f48efa8 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -53,14 +53,14 @@ export class SafetyCalculator { private onTrade = (ut: Models.Trade) => { var u = _.cloneDeep(ut); - if (this.isOlderThan(u, this._repo.latest)) return; + var older = this.isOlderThan(u, this._repo.latest); if (u.side === Models.Side.Ask) { - this._sells.push(u); + if (older) this._sells.push(u); this._sellsS.unshift(u); } else if (u.side === Models.Side.Bid) { - this._buys.push(u); + if (older) this._buys.push(u); this._buysS.unshift(u); } @@ -75,16 +75,6 @@ export class SafetyCalculator { private computeQtyLimit = () => { var settings = this._repo.latest; - var orderTrades = (input: Models.Trade[], direction: number): Models.Trade[]=> { - return _.chain(input) - .filter(o => !this.isOlderThan(o, settings)) - .sortBy((t: Models.Trade) => direction * t.price) - .value(); - }; - - this._buys = orderTrades(this._buys, -1); - this._sells = orderTrades(this._sells, 1); - var buyS = 0; var sellS = 0; var buySq = 0; @@ -109,6 +99,16 @@ export class SafetyCalculator { this._sellsS.slice(0,sSi); } + var orderTrades = (input: Models.Trade[], direction: number): Models.Trade[]=> { + return _.chain(input) + .filter(o => !this.isOlderThan(o, settings)) + .sortBy((t: Models.Trade) => direction * t.price) + .value(); + }; + + this._buys = orderTrades(this._buys, -1); + this._sells = orderTrades(this._sells, 1); + // don't count good trades against safety while (_.size(this._buys) > 0 && _.size(this._sells) > 0) { var sell = _.last(this._sells); @@ -131,7 +131,7 @@ export class SafetyCalculator { var computeSafety = (t: Models.Trade[]) => t.reduce((sum, t) => sum + t.quantity, 0) / this._qlParams.latest.size; - this.latest = new Models.TradeSafety(computeSafety(this._buys), computeSafety(this._sells), - buyS, sellS, computeSafety(this._buys.concat(this._sells)), this._timeProvider.utcNow()); + this.latest = new Models.TradeSafety(computeSafety(this._buys) || 0, computeSafety(this._sells) || 0, + buyS, sellS, computeSafety(this._buys.concat(this._sells)) || 0, this._timeProvider.utcNow()); }; } \ No newline at end of file From 54a07bf36cc43e4b41c468a71181e9b851b6f4bd Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 02:53:12 +0200 Subject: [PATCH 025/202] Fixed trades calc. --- src/service/safety.ts | 47 +++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index d3f48efa8..24492aa29 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -31,11 +31,6 @@ export class SafetyCalculator { } } - private _buys: Models.Trade[] = []; - private _sells: Models.Trade[] = []; - private _buysS: Models.Trade[] = []; - private _sellsS: Models.Trade[] = []; - constructor( private _timeProvider: Utils.ITimeProvider, private _repo: Interfaces.IRepository, @@ -53,15 +48,13 @@ export class SafetyCalculator { private onTrade = (ut: Models.Trade) => { var u = _.cloneDeep(ut); + if (this.isOlderThan(u, this._repo.latest)) return; - var older = this.isOlderThan(u, this._repo.latest); if (u.side === Models.Side.Ask) { - if (older) this._sells.push(u); - this._sellsS.unshift(u); + this._sells.push(u); } else if (u.side === Models.Side.Bid) { - if (older) this._buys.push(u); - this._buysS.unshift(u); + this._buys.push(u); } this.computeQtyLimit(); @@ -77,27 +70,25 @@ export class SafetyCalculator { var buyS = 0; var sellS = 0; + var buyi = 0; + var selli = 0; var buySq = 0; var sellSq = 0; - for (var bSi = 0; bSi < this._buysS.length; bSi++) { - if (buySq>settings.width) break; - buyS = this._buysS[bSi].price / this._buysS[bSi].quantity; - buySq += this._buysS[bSi].quantity; - } - if (bSi) { - buyS /= bSi; - this._buysS.slice(0,bSi); - } - - for (var sSi = 0; sSi < this._sellsS.length; sSi++) { - if (sellSq>settings.width) break; - sellS = this._sellsS[sSi].price / this._sellsS[sSi].quantity; - sellSq += this._sellsS[sSi].quantity; - } - if (sSi) { - sellS /= sSi; - this._sellsS.slice(0,sSi); + for (var ti = 0; ti < this._broker._trades.length; ti++) { + if (buySq>settings.size && sellSq>settings.size) break; + if (this._broker._trades[ti].side == Models.Side.Bid && buySq<=settings.size) { + buyS += (this._broker._trades[ti].price / this._broker._trades[ti].quantity); + buySq += this._broker._trades[ti].quantity; + buyi++: + } + if (this._broker._trades[ti].side == Models.Side.Ask && sellSq<=settings.size) { + sellS += (this._broker._trades[ti].price / this._broker._trades[ti].quantity); + sellSq += this._broker._trades[ti].quantity; + selli++; + } } + if (buyi) buyS /= buyi; + if (selli) sellS /= selli; var orderTrades = (input: Models.Trade[], direction: number): Models.Trade[]=> { return _.chain(input) From c5b1bde1983b91489407fd825d4c856b0d206db6 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 02:54:08 +0200 Subject: [PATCH 026/202] Fixed trades calc. --- src/service/safety.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index 24492aa29..1eaf4103a 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -79,7 +79,7 @@ export class SafetyCalculator { if (this._broker._trades[ti].side == Models.Side.Bid && buySq<=settings.size) { buyS += (this._broker._trades[ti].price / this._broker._trades[ti].quantity); buySq += this._broker._trades[ti].quantity; - buyi++: + buyi++; } if (this._broker._trades[ti].side == Models.Side.Ask && sellSq<=settings.size) { sellS += (this._broker._trades[ti].price / this._broker._trades[ti].quantity); From f25e5f65e788d421be79c437ba9c2bdc6f12bea4 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 02:56:14 +0200 Subject: [PATCH 027/202] Fixed trades calc. --- src/service/safety.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/service/safety.ts b/src/service/safety.ts index 1eaf4103a..ef4e83d9a 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -31,6 +31,9 @@ export class SafetyCalculator { } } + private _buys: Models.Trade[] = []; + private _sells: Models.Trade[] = []; + constructor( private _timeProvider: Utils.ITimeProvider, private _repo: Interfaces.IRepository, From 5aee9ad0fdb06fe4bcc9ae2d62f0f7f8cd5c30a6 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 03:12:18 +0200 Subject: [PATCH 028/202] Fixed trades calc. --- src/service/safety.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index ef4e83d9a..da3445cb2 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -37,7 +37,7 @@ export class SafetyCalculator { constructor( private _timeProvider: Utils.ITimeProvider, private _repo: Interfaces.IRepository, - private _broker: Interfaces.ITradeBroker, + private _broker: Interfaces.IOrderBroker, private _qlParams: Interfaces.IRepository, private _publisher: Messaging.IPublish, private _persister: Persister.IPersist) { From 876b286121c723c316e303b44a742e6eaf19407e Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 03:22:04 +0200 Subject: [PATCH 029/202] Fixed trades calc. --- src/service/safety.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index da3445cb2..7d4f47881 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -37,7 +37,7 @@ export class SafetyCalculator { constructor( private _timeProvider: Utils.ITimeProvider, private _repo: Interfaces.IRepository, - private _broker: Interfaces.IOrderBroker, + private _broker: Broker.OrderBroker, private _qlParams: Interfaces.IRepository, private _publisher: Messaging.IPublish, private _persister: Persister.IPersist) { From 0fbfd42bfc9f3389fed7deb5ec2165095c731285 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 04:02:16 +0200 Subject: [PATCH 030/202] Fixed trades calc. --- src/service/safety.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index 7d4f47881..32e674494 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -73,25 +73,21 @@ export class SafetyCalculator { var buyS = 0; var sellS = 0; - var buyi = 0; - var selli = 0; var buySq = 0; var sellSq = 0; for (var ti = 0; ti < this._broker._trades.length; ti++) { if (buySq>settings.size && sellSq>settings.size) break; if (this._broker._trades[ti].side == Models.Side.Bid && buySq<=settings.size) { - buyS += (this._broker._trades[ti].price / this._broker._trades[ti].quantity); + buyS += this._broker._trades[ti].price; buySq += this._broker._trades[ti].quantity; - buyi++; } if (this._broker._trades[ti].side == Models.Side.Ask && sellSq<=settings.size) { - sellS += (this._broker._trades[ti].price / this._broker._trades[ti].quantity); + sellS += this._broker._trades[ti].price; sellSq += this._broker._trades[ti].quantity; - selli++; } - } - if (buyi) buyS /= buyi; - if (selli) sellS /= selli; + } // BuyLT: 28,431.15, SellLT: 30,593.53 $14.118 + if (buySq) buyS /= buySq; + if (sellSq) sellS /= sellSq; var orderTrades = (input: Models.Trade[], direction: number): Models.Trade[]=> { return _.chain(input) From 50b76d3c36fd03bfbf9e4377a4e89dc6b4f4b6b5 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 20:57:11 +0200 Subject: [PATCH 031/202] Added debug. --- src/service/safety.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index 32e674494..1ace42eae 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -19,6 +19,8 @@ import Persister = require("./persister"); export class SafetyCalculator { NewValue = new Utils.Evt(); + private _log = Utils.log("safety"); + private _latest: Models.TradeSafety = null; public get latest() { return this._latest; } public set latest(val: Models.TradeSafety) { @@ -75,7 +77,11 @@ export class SafetyCalculator { var sellS = 0; var buySq = 0; var sellSq = 0; + this._log.info("!! Calc", this._broker._trades.length); for (var ti = 0; ti < this._broker._trades.length; ti++) { + this._log.info("!! Side", this._broker._trades[ti].side == Models.Side.Bid); + this._log.info("!! Price", this._broker._trades[ti].price); + this._log.info("!! Quantity", this._broker._trades[ti].quantity); if (buySq>settings.size && sellSq>settings.size) break; if (this._broker._trades[ti].side == Models.Side.Bid && buySq<=settings.size) { buyS += this._broker._trades[ti].price; @@ -85,9 +91,18 @@ export class SafetyCalculator { sellS += this._broker._trades[ti].price; sellSq += this._broker._trades[ti].quantity; } - } // BuyLT: 28,431.15, SellLT: 30,593.53 $14.118 + this._log.info("!! buyS", buyS); + this._log.info("!! buySq", buySq); + this._log.info("!! sellS", sellS); + this._log.info("!! sellSq", sellSq); + } + if (buySq) buyS /= buySq; if (sellSq) sellS /= sellSq; + this._log.info("!! buyS", buyS); + this._log.info("!! buySq", buySq); + this._log.info("!! sellS", sellS); + this._log.info("!! sellSq", sellSq); var orderTrades = (input: Models.Trade[], direction: number): Models.Trade[]=> { return _.chain(input) From 19254bca01df1a383293bd2f14b87eadb64ff1e6 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 21:18:36 +0200 Subject: [PATCH 032/202] Added debug. --- src/service/safety.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/service/safety.ts b/src/service/safety.ts index 1ace42eae..d12fa4caf 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -80,6 +80,7 @@ export class SafetyCalculator { this._log.info("!! Calc", this._broker._trades.length); for (var ti = 0; ti < this._broker._trades.length; ti++) { this._log.info("!! Side", this._broker._trades[ti].side == Models.Side.Bid); + this._log.info("!! time", this._broker._trades[ti].time); this._log.info("!! Price", this._broker._trades[ti].price); this._log.info("!! Quantity", this._broker._trades[ti].quantity); if (buySq>settings.size && sellSq>settings.size) break; From ff6d7f3f1771e104012e74962952240bb6a9583c Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 21:30:51 +0200 Subject: [PATCH 033/202] Added debug. --- src/service/safety.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index d12fa4caf..d324c6b82 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -78,7 +78,7 @@ export class SafetyCalculator { var buySq = 0; var sellSq = 0; this._log.info("!! Calc", this._broker._trades.length); - for (var ti = 0; ti < this._broker._trades.length; ti++) { + for (var ti = this._broker._trades.length - 1; ti > -1; ti--) { this._log.info("!! Side", this._broker._trades[ti].side == Models.Side.Bid); this._log.info("!! time", this._broker._trades[ti].time); this._log.info("!! Price", this._broker._trades[ti].price); From 4fbe732b17904c38d9d9aa1b376b978a75600b83 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 21:49:08 +0200 Subject: [PATCH 034/202] Added debug. --- src/service/safety.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index d324c6b82..e25c8061f 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -85,11 +85,11 @@ export class SafetyCalculator { this._log.info("!! Quantity", this._broker._trades[ti].quantity); if (buySq>settings.size && sellSq>settings.size) break; if (this._broker._trades[ti].side == Models.Side.Bid && buySq<=settings.size) { - buyS += this._broker._trades[ti].price; + buyS += this._broker._trades[ti].price * this._broker._trades[ti].quantity; buySq += this._broker._trades[ti].quantity; } if (this._broker._trades[ti].side == Models.Side.Ask && sellSq<=settings.size) { - sellS += this._broker._trades[ti].price; + sellS += this._broker._trades[ti].price * this._broker._trades[ti].quantity; sellSq += this._broker._trades[ti].quantity; } this._log.info("!! buyS", buyS); From 0035b160583251117c3d50d3e306a09058b05c01 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 21:52:08 +0200 Subject: [PATCH 035/202] Thank you debug\! --- src/service/safety.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index e25c8061f..4e9bc3357 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -77,12 +77,7 @@ export class SafetyCalculator { var sellS = 0; var buySq = 0; var sellSq = 0; - this._log.info("!! Calc", this._broker._trades.length); for (var ti = this._broker._trades.length - 1; ti > -1; ti--) { - this._log.info("!! Side", this._broker._trades[ti].side == Models.Side.Bid); - this._log.info("!! time", this._broker._trades[ti].time); - this._log.info("!! Price", this._broker._trades[ti].price); - this._log.info("!! Quantity", this._broker._trades[ti].quantity); if (buySq>settings.size && sellSq>settings.size) break; if (this._broker._trades[ti].side == Models.Side.Bid && buySq<=settings.size) { buyS += this._broker._trades[ti].price * this._broker._trades[ti].quantity; @@ -92,18 +87,10 @@ export class SafetyCalculator { sellS += this._broker._trades[ti].price * this._broker._trades[ti].quantity; sellSq += this._broker._trades[ti].quantity; } - this._log.info("!! buyS", buyS); - this._log.info("!! buySq", buySq); - this._log.info("!! sellS", sellS); - this._log.info("!! sellSq", sellSq); } if (buySq) buyS /= buySq; if (sellSq) sellS /= sellSq; - this._log.info("!! buyS", buyS); - this._log.info("!! buySq", buySq); - this._log.info("!! sellS", sellS); - this._log.info("!! sellSq", sellSq); var orderTrades = (input: Models.Trade[], direction: number): Models.Trade[]=> { return _.chain(input) From 4d7338178f72bbc98a0bfd1880c7fc45aa70b774 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 22:26:40 +0200 Subject: [PATCH 036/202] Fixed max calc. --- src/service/safety.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index 4e9bc3357..40960153b 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -76,17 +76,17 @@ export class SafetyCalculator { var buyS = 0; var sellS = 0; var buySq = 0; - var sellSq = 0; + var sellSq = 0; // BuyLT: 375.76, SellLT: 376.97 $157.055 for (var ti = this._broker._trades.length - 1; ti > -1; ti--) { - if (buySq>settings.size && sellSq>settings.size) break; - if (this._broker._trades[ti].side == Models.Side.Bid && buySq<=settings.size) { + if (this._broker._trades[ti].side == Models.Side.Bid && buySq=settings.size && sellSq>=settings.size) break; } if (buySq) buyS /= buySq; From 1a23171e61c9ce56d1338e91ad52dca44715a428 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 12 Apr 2016 22:37:12 +0200 Subject: [PATCH 037/202] Fixed max calc. --- src/service/safety.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index 40960153b..a6eeffe5c 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -76,15 +76,19 @@ export class SafetyCalculator { var buyS = 0; var sellS = 0; var buySq = 0; - var sellSq = 0; // BuyLT: 375.76, SellLT: 376.97 $157.055 + var sellSq = 0; + var _buySq = 0; + var _sellSq = 0; for (var ti = this._broker._trades.length - 1; ti > -1; ti--) { if (this._broker._trades[ti].side == Models.Side.Bid && buySq=settings.size && sellSq>=settings.size) break; } From 5ea09aa4a0c8d6f799652788f07fffdaee4e33cd Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 13 Apr 2016 00:44:14 +0200 Subject: [PATCH 038/202] Fixed calc display. --- src/service/safety.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index a6eeffe5c..2b153e1fa 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -24,7 +24,9 @@ export class SafetyCalculator { private _latest: Models.TradeSafety = null; public get latest() { return this._latest; } public set latest(val: Models.TradeSafety) { - if (!this._latest || Math.abs(val.combined - this._latest.combined) > 1e-3) { + if (!this._latest || Math.abs(val.combined - this._latest.combined) > 1e-3 + || Math.abs(val.buyS - this._latest.buyS) >= 1e-2 + || Math.abs(val.sellS - this._latest.sellS) >= 1e-2) { this._latest = val; this.NewValue.trigger(this.latest); From e8a1aeb9cc97e60cd33b243eded8e99efe72dfa8 Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 13 Apr 2016 01:06:58 +0200 Subject: [PATCH 039/202] Added PingPong calc. --- src/admin/trade-safety.ts | 2 +- src/service/quoting-engine.ts | 29 +++++++++++++++++------------ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/admin/trade-safety.ts b/src/admin/trade-safety.ts index 92284a611..894779946 100644 --- a/src/admin/trade-safety.ts +++ b/src/admin/trade-safety.ts @@ -55,7 +55,7 @@ export var tradeSafetyDirective = "tradeSafetyDirective"; angular .module(tradeSafetyDirective, ['sharedDirectives']) .directive("tradeSafety", () => { - var template = 'BuyLT: {{ buySizeSafety|number:2 }}, SellLT: {{ sellSizeSafety|number:2 }}, BuyTS: {{ buySafety|number:2 }}, SellTS: {{ sellSafety|number:2 }}, TotalTS: {{ tradeSafetyValue|number:2 }}'; + var template = 'BuyLT: {{ buySizeSafety|number:2 }}, SellLT: {{ sellSizeSafety|number:2 }}, BuyTS: {{ buySafety|number:2 }}, SellTS: {{ sellSafety|number:2 }}, TotalTS: {{ tradeSafetyValue|number:2 }}'; return { restrict: 'E', diff --git a/src/service/quoting-engine.ts b/src/service/quoting-engine.ts index 98b32c5cf..14207b526 100644 --- a/src/service/quoting-engine.ts +++ b/src/service/quoting-engine.ts @@ -88,20 +88,18 @@ export class QuotingEngine { } } - // if (params.mode === Models.QuotingMode.Top || params.mode === Models.QuotingMode.InverseTop) { - for (var fai = 0; fai < Math.min(42, filteredMkt.asks.length); fai++) { - if (filteredMkt.asks[fai].price > unrounded.askPx) { - unrounded.askPx = filteredMkt.asks[fai].price - .01; - break; - } + for (var fai = 0; fai < Math.min(42, filteredMkt.asks.length); fai++) { + if (filteredMkt.asks[fai].price > unrounded.askPx) { + unrounded.askPx = filteredMkt.asks[fai].price - .01; + break; } - for (var fbi = 0; fbi < Math.min(42, filteredMkt.bids.length); fbi++) { - if (filteredMkt.bids[fbi].price < unrounded.bidPx) { - unrounded.bidPx = filteredMkt.bids[fbi].price + .01; - break; - } + } + for (var fbi = 0; fbi < Math.min(42, filteredMkt.bids.length); fbi++) { + if (filteredMkt.bids[fbi].price < unrounded.bidPx) { + unrounded.bidPx = filteredMkt.bids[fbi].price + .01; + break; } - // } + } var tbp = this._targetPosition.latestTargetPosition; if (tbp === null) { @@ -133,6 +131,13 @@ export class QuotingEngine { return null; } + if (params.mode === Models.QuotingMode.PingPong) { + if (unrounded.bidPx > safety.sellS - params.width) + unrounded.bidPx = safety.sellS - params.width; + if (unrounded.askPx > safety.buyS + params.width) + unrounded.askPx = safety.buyS + params.width; + } + if (safety.sell > params.tradesPerMinute) { unrounded.askPx = null; unrounded.askSz = null; From 53174fdd819812a76d060071e0a8cdadd06c9b51 Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 13 Apr 2016 01:19:14 +0200 Subject: [PATCH 040/202] Fixed morning typo. --- src/service/quoting-engine.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/quoting-engine.ts b/src/service/quoting-engine.ts index 14207b526..5b41bd92b 100644 --- a/src/service/quoting-engine.ts +++ b/src/service/quoting-engine.ts @@ -134,7 +134,7 @@ export class QuotingEngine { if (params.mode === Models.QuotingMode.PingPong) { if (unrounded.bidPx > safety.sellS - params.width) unrounded.bidPx = safety.sellS - params.width; - if (unrounded.askPx > safety.buyS + params.width) + if (unrounded.askPx < safety.buyS + params.width) unrounded.askPx = safety.buyS + params.width; } From c3dd43695aa8f9bc12f33869ac746ec6c142c6ec Mon Sep 17 00:00:00 2001 From: ctubio Date: Thu, 14 Apr 2016 22:09:41 +0200 Subject: [PATCH 041/202] Fixed price accommodation. --- src/service/quoting-engine.ts | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/service/quoting-engine.ts b/src/service/quoting-engine.ts index 5b41bd92b..37605a8a0 100644 --- a/src/service/quoting-engine.ts +++ b/src/service/quoting-engine.ts @@ -88,19 +88,6 @@ export class QuotingEngine { } } - for (var fai = 0; fai < Math.min(42, filteredMkt.asks.length); fai++) { - if (filteredMkt.asks[fai].price > unrounded.askPx) { - unrounded.askPx = filteredMkt.asks[fai].price - .01; - break; - } - } - for (var fbi = 0; fbi < Math.min(42, filteredMkt.bids.length); fbi++) { - if (filteredMkt.bids[fbi].price < unrounded.bidPx) { - unrounded.bidPx = filteredMkt.bids[fbi].price + .01; - break; - } - } - var tbp = this._targetPosition.latestTargetPosition; if (tbp === null) { this._log.warn("cannot compute a quote since no position report exists!"); @@ -138,6 +125,21 @@ export class QuotingEngine { unrounded.askPx = safety.buyS + params.width; } + if (unrounded.askPx !== null) + for (var fai = 0; fai < filteredMkt.asks.length; fai++) { + if (filteredMkt.asks[fai].price > unrounded.askPx) { + unrounded.askPx = filteredMkt.asks[fai].price - .01; + break; + } + } + if (unrounded.bidPx !== null) + for (var fbi = 0; fbi < filteredMkt.bids.length; fbi++) { + if (filteredMkt.bids[fbi].price < unrounded.bidPx) { + unrounded.bidPx = filteredMkt.bids[fbi].price + .01; + break; + } + } + if (safety.sell > params.tradesPerMinute) { unrounded.askPx = null; unrounded.askSz = null; From 80491ad8254883c3c049dcf0f787be9d4d44488e Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 17 Apr 2016 19:20:46 +0200 Subject: [PATCH 042/202] Merge remote-tracking branch 'upstream/master'. --- src/common/models.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/common/models.ts b/src/common/models.ts index e2f0b750e..f113282fb 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -382,8 +382,6 @@ export class RegularFairValue { export class TradeSafety { constructor(public buy: number, public sell: number, - public buyS: number, - public sellS: number, public combined: number, public buyPing: number, public sellPong: number, From f70ad4ab796662c98ee294ba7992549773bc79e0 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 17 Apr 2016 20:05:31 +0200 Subject: [PATCH 043/202] Merge remote-tracking branch 'upstream/master'. --- src/service/quoting-engine.ts | 8 ++++---- src/service/quoting-styles/top-join.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/service/quoting-engine.ts b/src/service/quoting-engine.ts index 37605a8a0..b5eb9299b 100644 --- a/src/service/quoting-engine.ts +++ b/src/service/quoting-engine.ts @@ -119,10 +119,10 @@ export class QuotingEngine { } if (params.mode === Models.QuotingMode.PingPong) { - if (unrounded.bidPx > safety.sellS - params.width) - unrounded.bidPx = safety.sellS - params.width; - if (unrounded.askPx < safety.buyS + params.width) - unrounded.askPx = safety.buyS + params.width; + if (safety.buyPing && unrounded.askPx < safety.buyPing + params.width) + unrounded.askPx = safety.buyPing + params.width; + if (safety.sellPong && unrounded.bidPx > safety.sellPong - params.width) + unrounded.bidPx = safety.sellPong - params.width; } if (unrounded.askPx !== null) diff --git a/src/service/quoting-styles/top-join.ts b/src/service/quoting-styles/top-join.ts index 2e2fdb102..b1e6d1031 100644 --- a/src/service/quoting-styles/top-join.ts +++ b/src/service/quoting-styles/top-join.ts @@ -111,14 +111,14 @@ function computePingPongQuote(filteredMkt: Models.Market, fv: Models.FairValue, genQt.bidPx += .01; } - var minBid = fv.price - params.width / 2.0; + var minBid = fv.price - params.width / 4.0; genQt.bidPx = Math.min(minBid, genQt.bidPx); if (params.mode === Models.QuotingMode.PingPong && genQt.askSz > .2) { genQt.askPx -= .01; } - var minAsk = fv.price + params.width / 2.0; + var minAsk = fv.price + params.width / 4.0; genQt.askPx = Math.max(minAsk, genQt.askPx); genQt.bidSz = params.size; From 067095fae136e9806eca7953aaea0def08463ed3 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 17 Apr 2016 21:13:13 +0200 Subject: [PATCH 044/202] Fixed displays. --- src/admin/trade-safety.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/admin/trade-safety.ts b/src/admin/trade-safety.ts index 894779946..f4d8826f0 100644 --- a/src/admin/trade-safety.ts +++ b/src/admin/trade-safety.ts @@ -26,8 +26,8 @@ var TradeSafetyController = ($scope : TradeSafetyScope, $log : ng.ILogService, s $scope.tradeSafetyValue = value.combined; $scope.buySafety = value.buy; $scope.sellSafety = value.sell; - $scope.buySizeSafety = value.buyS; - $scope.sellSizeSafety = value.sellS; + $scope.buySizeSafety = value.buyPing; + $scope.sellSizeSafety = value.sellPong; }; var clear = () => { From 5b8e7e9c1e3f4211b70231e7ba57d4e1d28ac6e5 Mon Sep 17 00:00:00 2001 From: ctubio Date: Mon, 18 Apr 2016 13:46:55 +0200 Subject: [PATCH 045/202] Fixed calc. --- src/service/quoting-styles/top-join.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/quoting-styles/top-join.ts b/src/service/quoting-styles/top-join.ts index b1e6d1031..59eaee74c 100644 --- a/src/service/quoting-styles/top-join.ts +++ b/src/service/quoting-styles/top-join.ts @@ -111,14 +111,14 @@ function computePingPongQuote(filteredMkt: Models.Market, fv: Models.FairValue, genQt.bidPx += .01; } - var minBid = fv.price - params.width / 4.0; + var minBid = fv.price - params.width / 6.0; genQt.bidPx = Math.min(minBid, genQt.bidPx); if (params.mode === Models.QuotingMode.PingPong && genQt.askSz > .2) { genQt.askPx -= .01; } - var minAsk = fv.price + params.width / 4.0; + var minAsk = fv.price + params.width / 6.0; genQt.askPx = Math.max(minAsk, genQt.askPx); genQt.bidSz = params.size; From 7d5d113a9255625dfb4a3a741c54a5f3a6fc5b40 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 6 May 2016 01:23:32 +0200 Subject: [PATCH 046/202] Fixed calc. --- src/service/quoting-styles/top-join.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/quoting-styles/top-join.ts b/src/service/quoting-styles/top-join.ts index 59eaee74c..8e2f544e2 100644 --- a/src/service/quoting-styles/top-join.ts +++ b/src/service/quoting-styles/top-join.ts @@ -111,14 +111,14 @@ function computePingPongQuote(filteredMkt: Models.Market, fv: Models.FairValue, genQt.bidPx += .01; } - var minBid = fv.price - params.width / 6.0; + var minBid = fv.price - params.width / 8.0; genQt.bidPx = Math.min(minBid, genQt.bidPx); if (params.mode === Models.QuotingMode.PingPong && genQt.askSz > .2) { genQt.askPx -= .01; } - var minAsk = fv.price + params.width / 6.0; + var minAsk = fv.price + params.width / 8.0; genQt.askPx = Math.max(minAsk, genQt.askPx); genQt.bidSz = params.size; From 798061160ccfb6825f31466165d0a62134c89479 Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 25 May 2016 01:57:43 +0200 Subject: [PATCH 047/202] Fixed new ETH. --- src/service/gateways/coinbase.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/service/gateways/coinbase.ts b/src/service/gateways/coinbase.ts index 2203ef2a7..0de1366f1 100644 --- a/src/service/gateways/coinbase.ts +++ b/src/service/gateways/coinbase.ts @@ -475,7 +475,7 @@ class CoinbaseOrderEntryGateway implements Interfaces.IOrderEntryGateway { leavesQuantity: 0 }); } - + d.resolve(resp.length); }; }); @@ -580,23 +580,23 @@ class CoinbaseOrderEntryGateway implements Interfaces.IOrderEntryGateway { size: order.quantity.toString(), product_id: this._symbolProvider.symbol }; - + if (order.type === Models.OrderType.Limit) { o.price = order.price.toString(); - + if (order.preferPostOnly) o.post_only = true; - + switch (order.timeInForce) { - case Models.TimeInForce.GTC: + case Models.TimeInForce.GTC: break; - case Models.TimeInForce.FOK: + case Models.TimeInForce.FOK: o.time_in_force = "FOK"; break; - case Models.TimeInForce.IOC: + case Models.TimeInForce.IOC: o.time_in_force = "IOC"; break; - default: + default: throw new Error("Cannot map " + Models.TimeInForce[order.timeInForce] + " to a coinbase TIF"); } } @@ -739,15 +739,15 @@ class CoinbasePositionGateway implements Interfaces.IPositionGateway { private onTick = () => { this._authClient.getAccounts((err?: Error, resp?: any, data?: CoinbaseAccountInformation[]) => { - try { _.forEach(data, d => { + try { var c = GetCurrencyEnum(d.currency); var rpt = new Models.CurrencyPosition(convertPrice(d.available), convertPrice(d.hold), c); this.PositionUpdate.trigger(rpt); - }); } catch (error) { this._log.error(error, "Exception while downloading Coinbase positions", data) } + }); }); }; From 32cbfc28c4afb06eb14c25b70fc58049c3f68dd6 Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 25 May 2016 02:07:42 +0200 Subject: [PATCH 048/202] Fixed new ETH. --- src/service/gateways/coinbase.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/service/gateways/coinbase.ts b/src/service/gateways/coinbase.ts index 0de1366f1..8ed3218d9 100644 --- a/src/service/gateways/coinbase.ts +++ b/src/service/gateways/coinbase.ts @@ -739,15 +739,18 @@ class CoinbasePositionGateway implements Interfaces.IPositionGateway { private onTick = () => { this._authClient.getAccounts((err?: Error, resp?: any, data?: CoinbaseAccountInformation[]) => { - _.forEach(data, d => { try { + _.forEach(data, d => { var c = GetCurrencyEnum(d.currency); - var rpt = new Models.CurrencyPosition(convertPrice(d.available), convertPrice(d.hold), c); - this.PositionUpdate.trigger(rpt); + if (c) { + var rpt = new Models.CurrencyPosition(convertPrice(d.available), convertPrice(d.hold), c); + this.PositionUpdate.trigger(rpt); + } + else this._log.error(error, "Exception while downloading Coinbase positions", data) + }); } catch (error) { this._log.error(error, "Exception while downloading Coinbase positions", data) } - }); }); }; @@ -796,7 +799,7 @@ function GetCurrencyEnum(name: string): Models.Currency { case "USD": return Models.Currency.USD; case "EUR": return Models.Currency.EUR; case "GBP": return Models.Currency.GBP; - default: throw new Error("Unsupported currency " + name); + default: return false; } } From 0a84d5bab3fe28927319f9db4ce37faaeffd7a98 Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 25 May 2016 02:09:33 +0200 Subject: [PATCH 049/202] Fixed new ETH. --- src/service/gateways/coinbase.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/service/gateways/coinbase.ts b/src/service/gateways/coinbase.ts index 8ed3218d9..c4feb6e4d 100644 --- a/src/service/gateways/coinbase.ts +++ b/src/service/gateways/coinbase.ts @@ -746,7 +746,9 @@ class CoinbasePositionGateway implements Interfaces.IPositionGateway { var rpt = new Models.CurrencyPosition(convertPrice(d.available), convertPrice(d.hold), c); this.PositionUpdate.trigger(rpt); } - else this._log.error(error, "Exception while downloading Coinbase positions", data) + else { + this._log.error('ERROR CoinbasePositionGateway function', "Exception while downloading Coinbase positions", data); + } }); } catch (error) { this._log.error(error, "Exception while downloading Coinbase positions", data) From f390d154ed4075ad9ee8963e481fea84bc60fcee Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 25 May 2016 02:12:07 +0200 Subject: [PATCH 050/202] Fixed new ETH. --- src/common/models.ts | 2 +- src/service/gateways/coinbase.ts | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/common/models.ts b/src/common/models.ts index f113282fb..a02b873e4 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -58,7 +58,7 @@ export class MarketTrade implements ITimestamped { } export enum GatewayType { MarketData, OrderEntry, Position } -export enum Currency { USD, BTC, LTC, EUR, GBP, CNY } +export enum Currency { USD, BTC, LTC, EUR, GBP, CNY , ETH } export enum ConnectivityStatus { Connected, Disconnected } export enum Exchange { Null, HitBtc, OkCoin, AtlasAts, BtcChina, Coinbase, Bitfinex } export enum Side { Bid, Ask, Unknown } diff --git a/src/service/gateways/coinbase.ts b/src/service/gateways/coinbase.ts index c4feb6e4d..cc5db87e0 100644 --- a/src/service/gateways/coinbase.ts +++ b/src/service/gateways/coinbase.ts @@ -742,13 +742,8 @@ class CoinbasePositionGateway implements Interfaces.IPositionGateway { try { _.forEach(data, d => { var c = GetCurrencyEnum(d.currency); - if (c) { - var rpt = new Models.CurrencyPosition(convertPrice(d.available), convertPrice(d.hold), c); - this.PositionUpdate.trigger(rpt); - } - else { - this._log.error('ERROR CoinbasePositionGateway function', "Exception while downloading Coinbase positions", data); - } + var rpt = new Models.CurrencyPosition(convertPrice(d.available), convertPrice(d.hold), c); + this.PositionUpdate.trigger(rpt); }); } catch (error) { this._log.error(error, "Exception while downloading Coinbase positions", data) @@ -801,7 +796,8 @@ function GetCurrencyEnum(name: string): Models.Currency { case "USD": return Models.Currency.USD; case "EUR": return Models.Currency.EUR; case "GBP": return Models.Currency.GBP; - default: return false; + case "ETH": return Models.Currency.GBP; + default: throw new Error("Unsupported currency " + name); } } @@ -811,6 +807,7 @@ function GetCurrencySymbol(c: Models.Currency): string { case Models.Currency.GBP: return "GBP"; case Models.Currency.BTC: return "BTC"; case Models.Currency.EUR: return "EUR"; + case Models.Currency.ETH: return "ETH"; default: throw new Error("Unsupported currency " + Models.Currency[c]); } } From 093edfa619de04ce50dae593223bc64d13c51134 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 00:34:48 +0200 Subject: [PATCH 051/202] Added Boomerang quoting style. --- src/admin/trades.ts | 5 +++- src/common/models.ts | 3 ++- src/service/broker.ts | 10 ++++---- src/service/main.ts | 1 + src/service/quoting-engine.ts | 2 +- src/service/quoting-styles/top-join.ts | 32 ++++++++++++++++++++++++++ 6 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index c24022a90..30a77df6f 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -24,6 +24,7 @@ class DisplayTrade { side : string; value : number; liquidity : string; + alloc : number; constructor($scope : TradesScope, public trade : Models.Trade) { this.tradeId = trade.tradeId; @@ -31,6 +32,7 @@ class DisplayTrade { this.time = (moment.isMoment(trade.time) ? trade.time : moment(trade.time)); this.price = trade.price; this.quantity = trade.quantity; + this.alloc = 0; this.value = trade.value; if (trade.liquidity === 0 || trade.liquidity === 1) { @@ -75,7 +77,8 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri } }}, {width: 30, field:'liquidity', displayName:'liq'}, - {width: 60, field:'value', displayName:'val', cellFilter: 'currency:"$":3'} + {width: 60, field:'value', displayName:'val', cellFilter: 'currency:"$":3'}, + {width: 50, field:'alloc', displayName:'alloc'} ] }; diff --git a/src/common/models.ts b/src/common/models.ts index a02b873e4..5e84ddaaa 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -250,6 +250,7 @@ export class Trade implements ITimestamped { public side: Side, public value: number, public liquidity: Liquidity, + public alloc: number, public feeCharged: number) {} } @@ -332,7 +333,7 @@ export function currencyPairEqual(a: CurrencyPair, b: CurrencyPair): boolean { return a.base === b.base && a.quote === b.quote; } -export enum QuotingMode { Top, Mid, Join, InverseJoin, InverseTop, PingPong } +export enum QuotingMode { Top, Mid, Join, InverseJoin, InverseTop, PingPong, Boomerang } export enum FairValueModel { BBO, wBBO } export enum AutoPositionMode { Off, EwmaBasic } diff --git a/src/service/broker.ts b/src/service/broker.ts index 0c76411cc..0ef9f4002 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -100,7 +100,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { sendOrder = (order : Models.SubmitNewOrder) : Models.SentOrder => { var orderId = this._oeGateway.generateClientOrderId(); var exch = this._baseBroker.exchange(); - var brokeredOrder = new Models.BrokeredOrder(orderId, order.side, order.quantity, order.type, + var brokeredOrder = new Models.BrokeredOrder(orderId, order.side, order.quantity, order.type, order.price, order.timeInForce, exch, order.preferPostOnly); var sent = this._oeGateway.sendOrder(brokeredOrder); @@ -126,7 +126,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { replaceOrder = (replace : Models.CancelReplaceOrder) : Models.SentOrder => { var rpt = _.last(this._orderCache.allOrders[replace.origOrderId]); - var br = new Models.BrokeredReplace(replace.origOrderId, replace.origOrderId, rpt.side, replace.quantity, + var br = new Models.BrokeredReplace(replace.origOrderId, replace.origOrderId, rpt.side, replace.quantity, rpt.type, replace.price, rpt.timeInForce, rpt.exchange, rpt.exchangeId, rpt.preferPostOnly); var sent = this._oeGateway.replaceOrder(br); @@ -265,8 +265,8 @@ export class OrderBroker implements Interfaces.IOrderBroker { value = value * (1 + sign * feeCharged); } - const trade = new Models.Trade(o.orderId+"."+o.version, o.time, o.exchange, o.pair, - o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, feeCharged); + const trade = new Models.Trade(o.orderId+"."+o.version, o.time, o.exchange, o.pair, + o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, feeCharged); this.Trade.trigger(trade); this._tradePublisher.publish(trade); this._tradePersister.persist(trade); @@ -313,7 +313,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { this._log.error(e, "unhandled exception while submitting order", o); } }); - + _cancelOrderReciever.registerReceiver(o => { this._log.info("got new cancel req", o); try { diff --git a/src/service/main.ts b/src/service/main.ts index 32cdafadc..a9298ae01 100644 --- a/src/service/main.ts +++ b/src/service/main.ts @@ -352,6 +352,7 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { new TopJoin.JoinQuoteStyle(), new TopJoin.TopOfTheMarketQuoteStyle(), new TopJoin.PingPongQuoteStyle(), + new TopJoin.BoomerangQuoteStyle(), ]); var positionMgr = new PositionManagement.PositionManager(timeProvider, rfvPersister, fvEngine, initRfv, shortEwma, longEwma); diff --git a/src/service/quoting-engine.ts b/src/service/quoting-engine.ts index 433cce27b..2d5f57165 100644 --- a/src/service/quoting-engine.ts +++ b/src/service/quoting-engine.ts @@ -118,7 +118,7 @@ export class QuotingEngine { return null; } - if (params.mode === Models.QuotingMode.PingPong) { + if (params.mode === Models.QuotingMode.PingPong || params.mode === Models.QuotingMode.Boomerang) { if (unrounded.askSz && safety.buyPing && unrounded.askPx < safety.buyPing + params.width) unrounded.askPx = safety.buyPing + params.width; if (unrounded.bidSz && safety.sellPong && unrounded.bidPx > safety.sellPong - params.width) diff --git a/src/service/quoting-styles/top-join.ts b/src/service/quoting-styles/top-join.ts index 8e2f544e2..ac158ba1b 100644 --- a/src/service/quoting-styles/top-join.ts +++ b/src/service/quoting-styles/top-join.ts @@ -35,6 +35,14 @@ export class PingPongQuoteStyle implements StyleHelpers.QuoteStyle { }; } +export class BoomerangQuoteStyle implements StyleHelpers.QuoteStyle { + Mode = Models.QuotingMode.Boomerang; + + GenerateQuote = (market: Models.Market, fv: Models.FairValue, params: Models.QuotingParameters) : StyleHelpers.GeneratedQuote => { + return computeBoomerangQuote(market, fv, params); + }; +} + export class JoinQuoteStyle implements StyleHelpers.QuoteStyle { Mode = Models.QuotingMode.Join; @@ -124,5 +132,29 @@ function computePingPongQuote(filteredMkt: Models.Market, fv: Models.FairValue, genQt.bidSz = params.size; genQt.askSz = params.size; + return genQt; +} + +//computeBoomerangQuote is same as computeTopJoinQuote but need to use params.mode === Models.QuotingMode.PingPong +function computeBoomerangQuote(filteredMkt: Models.Market, fv: Models.FairValue, params: Models.QuotingParameters) { + var genQt = getQuoteAtTopOfMarket(filteredMkt, params); + + if (params.mode === Models.QuotingMode.Boomerang && genQt.bidSz > .2) { + genQt.bidPx += .01; + } + + var minBid = fv.price - params.width / 8.0; + genQt.bidPx = Math.min(minBid, genQt.bidPx); + + if (params.mode === Models.QuotingMode.Boomerang && genQt.askSz > .2) { + genQt.askPx -= .01; + } + + var minAsk = fv.price + params.width / 8.0; + genQt.askPx = Math.max(minAsk, genQt.askPx); + + genQt.bidSz = params.size; + genQt.askSz = params.size; + return genQt; } \ No newline at end of file From 7f59d04d147e2e523f8bf9763cfce9dc04aef92d Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 03:56:11 +0200 Subject: [PATCH 052/202] Added Boomerang calcs. --- src/admin/trades.ts | 20 ++++++++++++++----- src/service/broker.ts | 30 +++++++++++++++++++++++++--- src/service/main.ts | 8 ++++---- src/service/persister.ts | 42 ++++++++++++++++++++++++++++++++++++++++ src/service/safety.ts | 6 +++--- 5 files changed, 91 insertions(+), 15 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 30a77df6f..547a70fac 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -41,10 +41,6 @@ class DisplayTrade { else { this.liquidity = "?"; } - - if ($scope.sound) { - var audio = new Audio('http://antminer/a.mp3');audio.play(); - } } } @@ -82,7 +78,21 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri ] }; - var addTrade = t => $scope.trade_statuses.push(new DisplayTrade($scope, t)); + var addTrade = t => { + var exists = 0; + for(var i = 0;i<$scope.trade_statuses.length;i++) { + if ($scope.trade_statuses.tradeId==t.tradeId) { + exists = 1; + $scope.trade_statuses.alloc = t.alloc; + } + } + if (!exists) $scope.trade_statuses.push(new DisplayTrade($scope, t)); + if ($scope.sound) { + var audio = new Audio('http://antminer/a.mp3'); + audio.volume = 0.5; + audio.play(); + } + }; var sub = subscriberFactory.getSubscriber($scope, Messaging.Topics.Trades) .registerConnectHandler(() => $scope.trade_statuses.length = 0) diff --git a/src/service/broker.ts b/src/service/broker.ts index 0ef9f4002..63472da13 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -16,6 +16,7 @@ import Interfaces = require("./interfaces"); import Persister = require("./persister"); import util = require("util"); import Messages = require("./messages"); +import QuotingParameters = require("./quoting-parameters"); export class MarketDataBroker implements Interfaces.IMarketDataBroker { MarketData = new Utils.Evt(); @@ -268,9 +269,31 @@ export class OrderBroker implements Interfaces.IOrderBroker { const trade = new Models.Trade(o.orderId+"."+o.version, o.time, o.exchange, o.pair, o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, feeCharged); this.Trade.trigger(trade); - this._tradePublisher.publish(trade); - this._tradePersister.persist(trade); - this._trades.push(trade); + var reTrade = this._tradePersister.perfind(trade, this._qlParamRepo.latest.width); + if (reTrade==null||!reTrade) { + this._tradePublisher.publish(trade); + this._tradePersister.persist(trade); + this._trades.push(trade); + } else { + while (trade.quantity>0 && reTrade!=null && reTrade) { + for(var i = 0;i0) reTrade = this._tradePersister.perfind(trade, this._qlParamRepo.latest.width); + break; + } + } + } + if (trade.quantity>0) { + this._tradePublisher.publish(trade); + this._tradePublisher.persist(trade); + this._trades.push(trade); + } + } } }; @@ -286,6 +309,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { }; constructor(private _timeProvider: Utils.ITimeProvider, + private _qlParamRepo: QuotingParameters.QuotingParametersRepository, private _baseBroker : Interfaces.IBroker, private _oeGateway : Interfaces.IOrderEntryGateway, private _orderPersister : Persister.IPersist, diff --git a/src/service/main.ts b/src/service/main.ts index a9298ae01..240771a5a 100644 --- a/src/service/main.ts +++ b/src/service/main.ts @@ -320,15 +320,15 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { if (!_.some(gateway.base.supportedCurrencyPairs, p => p.base === pair.base && p.quote === pair.quote)) throw new Error("Unsupported currency pair!. Please check that gateway " + gateway.base.name() + " supports the value specified in TradedPair config value"); + var paramsRepo = new QuotingParameters.QuotingParametersRepository(quotingParametersPublisher, quotingParametersReceiver, initParams); + paramsRepo.NewParameters.on(() => paramsPersister.persist(paramsRepo.latest)); + var broker = new Broker.ExchangeBroker(pair, gateway.md, gateway.base, gateway.oe, connectivity); - var orderBroker = new Broker.OrderBroker(timeProvider, broker, gateway.oe, orderPersister, tradesPersister, orderStatusPublisher, + var orderBroker = new Broker.OrderBroker(timeProvider, paramsRepo, broker, gateway.oe, orderPersister, tradesPersister, orderStatusPublisher, tradePublisher, submitOrderReceiver, cancelOrderReceiver, cancelAllOrdersReceiver, messages, orderCache, initOrders, initTrades); var marketDataBroker = new Broker.MarketDataBroker(gateway.md, marketDataPublisher, marketDataPersister, messages); var positionBroker = new Broker.PositionBroker(timeProvider, broker, gateway.pg, positionPublisher, positionPersister, marketDataBroker); - var paramsRepo = new QuotingParameters.QuotingParametersRepository(quotingParametersPublisher, quotingParametersReceiver, initParams); - paramsRepo.NewParameters.on(() => paramsPersister.persist(paramsRepo.latest)); - var safetyCalculator = new Safety.SafetyCalculator(timeProvider, paramsRepo, orderBroker, paramsRepo, tradeSafetyPublisher, tsvPersister); var startQuoting = (timeProvider.utcNow().diff(initActive.time, 'minutes') < 3 && initActive.active); diff --git a/src/service/persister.ts b/src/service/persister.ts index df866e560..78c1b99c6 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -60,6 +60,8 @@ export interface ILoadLatest extends IPersist { } export interface ILoadAll extends IPersist { + perfind(data: T, width?: number): void; + repersist(data: T): void; loadAll(limit?: number, start_time?: moment.Moment): Q.Promise; } @@ -169,6 +171,46 @@ export class Persister implements ILoadAll { }).done(); }; + public perfind = (report: T, width?: number) => { + var deferred = Q.defer(); + this.collection.then(coll => { + this._saver(report); + coll.findOne({ $and: [ + price: report.side==Models.Side.Bid?{ $gt: width+report.price }:{ $lt: report.price-width }, + side: report.side==Models.Side.Bid?Models.Side.Ask:Models.Side.Bid, + $where: "this.quantity - this.alloc > 0" + ] }, err => { + if (err) deferred.reject(err); + if (err) + this._log.error(err, "Unable to prefind", this._dbName, report); + }).sort({ alloc: 1, price: report.side==Models.Side.Bid?-1:1 }) + .toArray((err, arr) => { + if (err) { + deferred.reject(err); + } + else if (arr.length === 0) { + deferred.resolve(null); + } + else { + this._loader(arr[0]); + deferred.resolve(arr[0]); + } + });; + }).done(); + + return deferred.promise; + }; + + public repersist = (report: T) => { + this.collection.then(coll => { + this._saver(report); + coll.findOneAndUpdate({ tradeId: report.tradeId }, { alloc : report.alloc }, err => { + if (err) + this._log.error(err, "Unable to repersist", this._dbName, report); + }); + }).done(); + }; + collection: Q.Promise; constructor( db: Q.Promise, diff --git a/src/service/safety.ts b/src/service/safety.ts index 771f2d8e2..82f0faebf 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -81,13 +81,13 @@ export class SafetyCalculator { var sellPq = 0; var _buyPq = 0; var _sellPq = 0; - for (var ti = this._broker._trades.length - 1; ti > -1; ti--) { - if (this._broker._trades[ti].side == Models.Side.Bid && buyPq -1); (settings.mode === Models.QuotingMode.Boomerang?ti++:ti--)) { + if ((settings.mode !== Models.QuotingMode.Boomerang || this._broker._trades[ti].alloc Date: Fri, 22 Jul 2016 03:59:34 +0200 Subject: [PATCH 053/202] Added Boomerang calcs. --- src/service/persister.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 78c1b99c6..44f7ae612 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -176,9 +176,9 @@ export class Persister implements ILoadAll { this.collection.then(coll => { this._saver(report); coll.findOne({ $and: [ - price: report.side==Models.Side.Bid?{ $gt: width+report.price }:{ $lt: report.price-width }, - side: report.side==Models.Side.Bid?Models.Side.Ask:Models.Side.Bid, - $where: "this.quantity - this.alloc > 0" + { price: report.side==Models.Side.Bid?{ $gt: width+report.price }:{ $lt: report.price-width } }, + { side: report.side==Models.Side.Bid?Models.Side.Ask:Models.Side.Bid }, + { $where: "this.quantity - this.alloc > 0" } ] }, err => { if (err) deferred.reject(err); if (err) From bb2ca0206f90b93b5692c54321ab7be011da8bed Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 04:04:56 +0200 Subject: [PATCH 054/202] Added Boomerang calcs. --- src/service/backtest.ts | 142 ++++++++++++++++++++------------------- src/service/persister.ts | 8 ++- 2 files changed, 79 insertions(+), 71 deletions(-) diff --git a/src/service/backtest.ts b/src/service/backtest.ts index 65123474d..f4d8e0233 100644 --- a/src/service/backtest.ts +++ b/src/service/backtest.ts @@ -24,49 +24,49 @@ enum TimedType { class Timed { constructor( - public action : () => void, - public time : moment.Moment, + public action : () => void, + public time : moment.Moment, public type : TimedType, public interval : moment.Duration) {} } export class BacktestTimeProvider implements Utils.IBacktestingTimeProvider { constructor(private _internalTime : moment.Moment, private _endTime : moment.Moment) { } - + utcNow = () => this._internalTime; - + private _immediates = new Array<() => void>(); setImmediate = (action: () => void) => this._immediates.push(action); - + private _timeouts : Timed[] = []; setTimeout = (action: () => void, time: moment.Duration) => { this.setAction(action, time, TimedType.Timeout); }; - + setInterval = (action: () => void, time: moment.Duration) => { this.setAction(action, time, TimedType.Interval); }; - + private setAction = (action: () => void, time: moment.Duration, type : TimedType) => { var dueTime = this._internalTime.clone().add(time); - + if (Utils.fastDiff(dueTime, this.utcNow()) < 0) { return; } - + this._timeouts.push(new Timed(action, dueTime, type, time)); this._timeouts.sort((a, b) => Utils.fastDiff(a.time, b.time)); }; - + scrollTimeTo = (time : moment.Moment) => { if (Utils.fastDiff(time, this.utcNow()) < 0) { throw new Error("Cannot reverse time!"); } - + while (this._immediates.length > 0) { this._immediates.pop()(); } - + while (this._timeouts.length > 0 && Utils.fastDiff(_.first(this._timeouts).time, time) < 0) { var evt : Timed = this._timeouts.shift(); this._internalTime = evt.time; @@ -75,28 +75,28 @@ export class BacktestTimeProvider implements Utils.IBacktestingTimeProvider { this.setAction(evt.action, evt.interval, evt.type); } } - + this._internalTime = time; }; } export class BacktestGateway implements Interfaces.IPositionGateway, Interfaces.IOrderEntryGateway, Interfaces.IMarketDataGateway { ConnectChanged = new Utils.Evt(); - + MarketData = new Utils.Evt(); MarketTrade = new Utils.Evt(); - + OrderUpdate = new Utils.Evt(); - + supportsCancelAllOpenOrders = () : boolean => { return false; }; cancelAllOpenOrders = () : Q.Promise => { return Q(0); }; - + generateClientOrderId = () => { return "BACKTEST-" + shortId.generate(); } public cancelsByClientOrderId = true; - + private _openBidOrders : {[orderId: string]: Models.BrokeredOrder} = {}; private _openAskOrders : {[orderId: string]: Models.BrokeredOrder} = {}; @@ -112,10 +112,10 @@ export class BacktestGateway implements Interfaces.IPositionGateway, Interfaces. this._baseHeld += order.quantity; this._baseAmount -= order.quantity; } - + this.OrderUpdate.trigger({ orderId: order.orderId, orderStatus: Models.OrderStatus.Working }); }, moment.duration(3)); - + return new Models.OrderGatewayActionReport(this.timeProvider.utcNow()); }; @@ -141,10 +141,10 @@ export class BacktestGateway implements Interfaces.IPositionGateway, Interfaces. this._baseAmount += existing.quantity; delete this._openAskOrders[cancel.clientOrderId]; } - + this.OrderUpdate.trigger({ orderId: cancel.clientOrderId, orderStatus: Models.OrderStatus.Cancelled }); }, moment.duration(3)); - + return new Models.OrderGatewayActionReport(this.timeProvider.utcNow()); }; @@ -152,26 +152,26 @@ export class BacktestGateway implements Interfaces.IPositionGateway, Interfaces. this.cancelOrder(new Models.BrokeredCancel(replace.origOrderId, replace.orderId, replace.side, replace.exchangeId)); return this.sendOrder(replace); }; - + private onMarketData = (market : Models.Market) => { this._openAskOrders = this.tryToMatch(_.values(this._openAskOrders), market.bids, Models.Side.Ask); this._openBidOrders = this.tryToMatch(_.values(this._openBidOrders), market.asks, Models.Side.Bid); - + this.MarketData.trigger(market); }; - + private tryToMatch = (orders: Models.BrokeredOrder[], marketSides: Models.MarketSide[], side: Models.Side) => { - if (orders.length === 0 || marketSides.length === 0) + if (orders.length === 0 || marketSides.length === 0) return _.indexBy(orders, k => k.orderId); - + var cmp = side === Models.Side.Ask ? (m, o) => o < m : (m, o) => o > m; _.forEach(orders, order => { _.forEach(marketSides, mkt => { if ((cmp(mkt.price, order.price) || order.type === Models.OrderType.Market) && order.quantity > 0) { - + var px = order.price; if (order.type === Models.OrderType.Market) px = mkt.price; - + var update : Models.OrderStatusReport = { orderId: order.orderId, lastPrice: px }; if (mkt.size >= order.quantity) { update.orderStatus = Models.OrderStatus.Complete; @@ -183,7 +183,7 @@ export class BacktestGateway implements Interfaces.IPositionGateway, Interfaces. update.lastQuantity = mkt.size; } this.OrderUpdate.trigger(update); - + if (side === Models.Side.Bid) { this._baseAmount += update.lastQuantity; this._quoteHeld -= (update.lastQuantity*px); @@ -192,66 +192,66 @@ export class BacktestGateway implements Interfaces.IPositionGateway, Interfaces. this._baseHeld -= update.lastQuantity; this._quoteAmount += (update.lastQuantity*px); } - + order.quantity = order.quantity - update.lastQuantity; }; }); }); - + var liveOrders = _.filter(orders, o => o.quantity > 0); - + if (liveOrders.length > 5) console.warn("more than 5 outstanding " + Models.Side[side] + " orders open"); - + return _.indexBy(liveOrders, k => k.orderId); }; - + private onMarketTrade = (trade : Models.MarketTrade) => { this._openAskOrders = this.tryToMatch(_.values(this._openAskOrders), [trade], Models.Side.Ask); this._openBidOrders = this.tryToMatch(_.values(this._openBidOrders), [trade], Models.Side.Bid); - + this.MarketTrade.trigger(new Models.GatewayMarketTrade(trade.price, trade.size, trade.time, false, trade.make_side)); }; - + PositionUpdate = new Utils.Evt(); private recomputePosition = () => { this.PositionUpdate.trigger(new Models.CurrencyPosition(this._baseAmount, this._baseHeld, Models.Currency.BTC)); this.PositionUpdate.trigger(new Models.CurrencyPosition(this._quoteAmount, this._quoteHeld, Models.Currency.USD)); }; - + private _baseHeld = 0; private _quoteHeld = 0; - + constructor( private _inputData: Array, private _baseAmount : number, private _quoteAmount : number, private timeProvider: Utils.IBacktestingTimeProvider) {} - + public run = () => { this.ConnectChanged.trigger(Models.ConnectivityStatus.Connected); - + var hasProcessedMktData = false; - + this.timeProvider.setInterval(() => this.recomputePosition(), moment.duration(15, "seconds")); - + _(this._inputData).forEach(i => { this.timeProvider.scrollTimeTo(i.time); - + if (typeof i["make_side"] !== "undefined") { this.onMarketTrade(i); } else if (typeof i["bids"] !== "undefined" || typeof i["asks"] !== "undefined") { this.onMarketData(i); - + if (!hasProcessedMktData) { this.recomputePosition(); hasProcessedMktData = true; } } }); - - this.recomputePosition(); + + this.recomputePosition(); }; } @@ -275,7 +275,7 @@ class BacktestGatewayDetails implements Interfaces.IExchangeDetailsGateway { exchange(): Models.Exchange { return Models.Exchange.Null; } - + private static AllPairs = [ new Models.CurrencyPair(Models.Currency.BTC, Models.Currency.USD) ]; @@ -293,10 +293,10 @@ export class BacktestParameters { export class BacktestPersister implements Persister.ILoadAll, Persister.ILoadLatest { public load = (exchange: Models.Exchange, pair: Models.CurrencyPair, limit?: number): Q.Promise => { - return this.loadAll(limit); + return this.loadAll(limit); }; - - public loadAll = (limit?: number): Q.Promise => { + + public loadAll = (limit?: number): Q.Promise => { if (this.initialData) { if (limit) { return Q(_.takeRight(this.initialData, limit)); @@ -307,14 +307,18 @@ export class BacktestPersister implements Persister.ILoadAll, Persister.IL } return Q([]); }; - + public persist = (report: T) => { }; - + + public perfind = (report: T, width: number) => { }; + + public repersist = (report: T) => { }; + public loadLatest = (): Q.Promise => { if (this.initialData) return Q(_.last(this.initialData)); }; - + constructor(private initialData?: T[]) { this.initialData = initialData || null; } @@ -324,7 +328,7 @@ export class BacktestExchange extends Interfaces.CombinedGateway { constructor(private gw: BacktestGateway) { super(gw, gw, gw, new BacktestGatewayDetails()); } - + public run = () => this.gw.run(); }; @@ -337,16 +341,16 @@ var backtestServer = () => { ["uncaughtException", "exit", "SIGINT", "SIGTERM"].forEach(reason => { process.on(reason, (e?) => { console.log(util.format("Terminating!", reason, e, (typeof e !== "undefined" ? e.stack : undefined))); - + process.exit(1); }); }); - + var mdFile = process.env['MD_FILE']; var paramFile = process.env['PARAM_FILE']; var savedProgressFile = process.env["PROGRESS_FILE"] || "nextParameters_saved.txt"; var backtestResultFile = process.env["RESULT_FILE"] || 'backtestResults.txt'; - + var rawParams = fs.readFileSync(paramFile, 'utf8'); var parameters : BacktestParameters[] = JSON.parse(rawParams); if (fs.existsSync(savedProgressFile)) { @@ -356,20 +360,20 @@ var backtestServer = () => { else if (fs.existsSync(backtestResultFile)) { fs.unlinkSync(backtestResultFile); } - + console.log("loaded input data..."); - + var app = express(); app.use(require('body-parser').json({limit: '200mb'})); app.use(require("compression")()); - + var server = app.listen(5001, () => { var host = server.address().address; var port = server.address().port; - + console.log('Backtest server listening at http://%s:%s', host, port); }); - + app.get("/inputData", (req, res) => { console.log("Starting inputData download for", req.ip); res.sendFile(mdFile, (err) => { @@ -377,18 +381,18 @@ var backtestServer = () => { else console.log("Ending inputData download for", req.ip); }); }); - + app.get("/nextParameters", (req, res) => { if (_.some(parameters)) { var id = parameters.length; var served = parameters.shift(); - if (typeof served["id"] === "undefined") + if (typeof served["id"] === "undefined") served.id = id.toString(); - + console.log("Serving parameters id =", served.id, " to", req.ip); res.json(served); fs.writeFileSync(savedProgressFile, parameters.length, {encoding: 'utf8'}); - + if (!_.some(parameters)) { console.log("Done serving parameters"); } @@ -399,10 +403,10 @@ var backtestServer = () => { fs.unlinkSync(savedProgressFile); } }); - + app.post("/result", (req, res) => { var params = req.body; - console.log("Accept backtest results, volume =", params[2].volume.toFixed(2), "val =", + console.log("Accept backtest results, volume =", params[2].volume.toFixed(2), "val =", params[1].value.toFixed(2), "qVal =", params[1].quoteValue.toFixed(2)); fs.appendFileSync(backtestResultFile, JSON.stringify(params)+"\n"); }); diff --git a/src/service/persister.ts b/src/service/persister.ts index 44f7ae612..da600b57c 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -53,6 +53,8 @@ export class LoaderSaver { export interface IPersist { persist(data: T): void; + perfind(data: T, width?: number): void; + repersist(data: T): void; } export interface ILoadLatest extends IPersist { @@ -60,8 +62,6 @@ export interface ILoadLatest extends IPersist { } export interface ILoadAll extends IPersist { - perfind(data: T, width?: number): void; - repersist(data: T): void; loadAll(limit?: number, start_time?: moment.Moment): Q.Promise; } @@ -94,6 +94,10 @@ export class RepositoryPersister implements ILoadLatest { }; + + public repersist = (report: T) => { }; + public persist = (report: T) => { this._saver(report); this.collection.then(coll => { From 938b5126783e3bc061364555e6f0b03d8ecbd870 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 04:06:54 +0200 Subject: [PATCH 055/202] Added Boomerang calcs. --- src/service/broker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 63472da13..e746c57d2 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -282,7 +282,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { this._trades[i].alloc += allocMod; trade.quantity -= allocMod; this._tradePublisher.publish(this._trades[i]); - this._tradePublisher.repersist(this._trades[i]); + this._tradePersister.repersist(this._trades[i]); if (trade.quantity>0) reTrade = this._tradePersister.perfind(trade, this._qlParamRepo.latest.width); break; } @@ -290,7 +290,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { } if (trade.quantity>0) { this._tradePublisher.publish(trade); - this._tradePublisher.persist(trade); + this._tradePersister.persist(trade); this._trades.push(trade); } } From fd55163a09d136e6bbdcca2292fea093ea44f840 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 04:09:19 +0200 Subject: [PATCH 056/202] Added Boomerang calcs. --- src/service/persister.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index da600b57c..97efcad72 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -179,7 +179,7 @@ export class Persister implements ILoadAll { var deferred = Q.defer(); this.collection.then(coll => { this._saver(report); - coll.findOne({ $and: [ + coll.find({ $and: [ { price: report.side==Models.Side.Bid?{ $gt: width+report.price }:{ $lt: report.price-width } }, { side: report.side==Models.Side.Bid?Models.Side.Ask:Models.Side.Bid }, { $where: "this.quantity - this.alloc > 0" } @@ -187,7 +187,7 @@ export class Persister implements ILoadAll { if (err) deferred.reject(err); if (err) this._log.error(err, "Unable to prefind", this._dbName, report); - }).sort({ alloc: 1, price: report.side==Models.Side.Bid?-1:1 }) + }).limit(1).sort({ alloc: 1, price: report.side==Models.Side.Bid?-1:1 }) .toArray((err, arr) => { if (err) { deferred.reject(err); From 0fad0770926892fc0f36ffe1467fe856401ff71f Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 04:16:08 +0200 Subject: [PATCH 057/202] Added Boomerang calcs. --- src/service/persister.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 97efcad72..2387856ae 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -183,11 +183,7 @@ export class Persister implements ILoadAll { { price: report.side==Models.Side.Bid?{ $gt: width+report.price }:{ $lt: report.price-width } }, { side: report.side==Models.Side.Bid?Models.Side.Ask:Models.Side.Bid }, { $where: "this.quantity - this.alloc > 0" } - ] }, err => { - if (err) deferred.reject(err); - if (err) - this._log.error(err, "Unable to prefind", this._dbName, report); - }).limit(1).sort({ alloc: 1, price: report.side==Models.Side.Bid?-1:1 }) + ] }).limit(1).sort({ alloc: 1, price: report.side==Models.Side.Bid?-1:1 }) .toArray((err, arr) => { if (err) { deferred.reject(err); From 16d619d81c1f5e6a4e8b34670e859794e348c672 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 04:24:31 +0200 Subject: [PATCH 058/202] Added Boomerang calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 2387856ae..80a8d3907 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -53,7 +53,7 @@ export class LoaderSaver { export interface IPersist { persist(data: T): void; - perfind(data: T, width?: number): void; + perfind(data: T, width?: number): Q.Promise; repersist(data: T): void; } From 95886b716d378eb00787e8193e7ac86103d1e4b4 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 04:28:01 +0200 Subject: [PATCH 059/202] Added Boomerang calcs. --- src/service/backtest.ts | 2 +- src/service/persister.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/service/backtest.ts b/src/service/backtest.ts index f4d8e0233..c8603773b 100644 --- a/src/service/backtest.ts +++ b/src/service/backtest.ts @@ -310,7 +310,7 @@ export class BacktestPersister implements Persister.ILoadAll, Persister.IL public persist = (report: T) => { }; - public perfind = (report: T, width: number) => { }; + public perfind = (report: T, width: number): Q.Promise => { }; public repersist = (report: T) => { }; diff --git a/src/service/persister.ts b/src/service/persister.ts index 80a8d3907..b25ae4b90 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -94,7 +94,7 @@ export class RepositoryPersister implements ILoadLatest { }; + public perfind = (report: T, width: number): Q.Promise => { }; public repersist = (report: T) => { }; @@ -175,7 +175,7 @@ export class Persister implements ILoadAll { }).done(); }; - public perfind = (report: T, width?: number) => { + public perfind = (report: T, width?: number): Q.Promise => { var deferred = Q.defer(); this.collection.then(coll => { this._saver(report); From 6d07003aa4a16abcbdf132328a91b68d11c57e02 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 04:29:15 +0200 Subject: [PATCH 060/202] Added Boomerang calcs. --- src/service/backtest.ts | 2 +- src/service/persister.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/backtest.ts b/src/service/backtest.ts index c8603773b..be19f5d5c 100644 --- a/src/service/backtest.ts +++ b/src/service/backtest.ts @@ -310,7 +310,7 @@ export class BacktestPersister implements Persister.ILoadAll, Persister.IL public persist = (report: T) => { }; - public perfind = (report: T, width: number): Q.Promise => { }; + public perfind = (report: T, width: number): any => { }; public repersist = (report: T) => { }; diff --git a/src/service/persister.ts b/src/service/persister.ts index b25ae4b90..2974bdb92 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -94,7 +94,7 @@ export class RepositoryPersister implements ILoadLatest => { }; + public perfind = (report: T, width: number): any => { }; public repersist = (report: T) => { }; From fb2adc789f340cc64fa50dade7aecc16bd9b3812 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 04:38:14 +0200 Subject: [PATCH 061/202] Added Boomerang calcs. --- src/service/persister.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 2974bdb92..d9b649b7e 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -53,7 +53,7 @@ export class LoaderSaver { export interface IPersist { persist(data: T): void; - perfind(data: T, width?: number): Q.Promise; + perfind(data: T, width?: number): any; repersist(data: T): void; } @@ -175,7 +175,7 @@ export class Persister implements ILoadAll { }).done(); }; - public perfind = (report: T, width?: number): Q.Promise => { + public perfind = (report: T, width?: number): any => { var deferred = Q.defer(); this.collection.then(coll => { this._saver(report); From cd28f402e6c91538d80279f038dcd58394f9950b Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 04:45:51 +0200 Subject: [PATCH 062/202] Added Boomerang calcs. --- src/service/persister.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index d9b649b7e..39c1a8938 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -178,7 +178,6 @@ export class Persister implements ILoadAll { public perfind = (report: T, width?: number): any => { var deferred = Q.defer(); this.collection.then(coll => { - this._saver(report); coll.find({ $and: [ { price: report.side==Models.Side.Bid?{ $gt: width+report.price }:{ $lt: report.price-width } }, { side: report.side==Models.Side.Bid?Models.Side.Ask:Models.Side.Bid }, From 275fa142b09ba484129e36d5986a2d8b5321e037 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 04:54:30 +0200 Subject: [PATCH 063/202] Added Boomerang calcs. --- src/service/backtest.ts | 4 ++-- src/service/broker.ts | 6 +++--- src/service/persister.ts | 16 ++++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/service/backtest.ts b/src/service/backtest.ts index be19f5d5c..8e36098e2 100644 --- a/src/service/backtest.ts +++ b/src/service/backtest.ts @@ -310,9 +310,9 @@ export class BacktestPersister implements Persister.ILoadAll, Persister.IL public persist = (report: T) => { }; - public perfind = (report: T, width: number): any => { }; + public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { }; - public repersist = (report: T) => { }; + public repersist = (report: T, tradeId: string, alloc?: number => { }; public loadLatest = (): Q.Promise => { if (this.initialData) diff --git a/src/service/broker.ts b/src/service/broker.ts index e746c57d2..949c7ffc8 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -269,7 +269,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { const trade = new Models.Trade(o.orderId+"."+o.version, o.time, o.exchange, o.pair, o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, feeCharged); this.Trade.trigger(trade); - var reTrade = this._tradePersister.perfind(trade, this._qlParamRepo.latest.width); + var reTrade = this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price); if (reTrade==null||!reTrade) { this._tradePublisher.publish(trade); this._tradePersister.persist(trade); @@ -282,8 +282,8 @@ export class OrderBroker implements Interfaces.IOrderBroker { this._trades[i].alloc += allocMod; trade.quantity -= allocMod; this._tradePublisher.publish(this._trades[i]); - this._tradePersister.repersist(this._trades[i]); - if (trade.quantity>0) reTrade = this._tradePersister.perfind(trade, this._qlParamRepo.latest.width); + this._tradePersister.repersist(this._trades[i], this._trades[i].tradeId, this._trades[i].alloc); + if (trade.quantity>0) reTrade = this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price); break; } } diff --git a/src/service/persister.ts b/src/service/persister.ts index 39c1a8938..94ac3d17a 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -53,7 +53,7 @@ export class LoaderSaver { export interface IPersist { persist(data: T): void; - perfind(data: T, width?: number): any; + perfind(report: T, side: Models.Side, width?: number, price?: number): any; repersist(data: T): void; } @@ -94,7 +94,7 @@ export class RepositoryPersister implements ILoadLatest { }; + public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { }; public repersist = (report: T) => { }; @@ -175,14 +175,14 @@ export class Persister implements ILoadAll { }).done(); }; - public perfind = (report: T, width?: number): any => { + public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { var deferred = Q.defer(); this.collection.then(coll => { coll.find({ $and: [ - { price: report.side==Models.Side.Bid?{ $gt: width+report.price }:{ $lt: report.price-width } }, - { side: report.side==Models.Side.Bid?Models.Side.Ask:Models.Side.Bid }, + { price: side==Models.Side.Bid?{ $gt: width+price }:{ $lt: price-width } }, + { side: side==Models.Side.Bid?Models.Side.Ask:Models.Side.Bid }, { $where: "this.quantity - this.alloc > 0" } - ] }).limit(1).sort({ alloc: 1, price: report.side==Models.Side.Bid?-1:1 }) + ] }).limit(1).sort({ alloc: 1, price: side==Models.Side.Bid?-1:1 }) .toArray((err, arr) => { if (err) { deferred.reject(err); @@ -200,10 +200,10 @@ export class Persister implements ILoadAll { return deferred.promise; }; - public repersist = (report: T) => { + public repersist = (report: T, tradeId: string, alloc?: number) => { this.collection.then(coll => { this._saver(report); - coll.findOneAndUpdate({ tradeId: report.tradeId }, { alloc : report.alloc }, err => { + coll.findOneAndUpdate({ tradeId: tradeId }, { alloc : alloc }, err => { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); From feb1694364575074e2c18cec803053a61f7e6623 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 04:55:52 +0200 Subject: [PATCH 064/202] Added Boomerang calcs. --- src/service/backtest.ts | 2 +- src/service/persister.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/service/backtest.ts b/src/service/backtest.ts index 8e36098e2..976c7eb0b 100644 --- a/src/service/backtest.ts +++ b/src/service/backtest.ts @@ -312,7 +312,7 @@ export class BacktestPersister implements Persister.ILoadAll, Persister.IL public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { }; - public repersist = (report: T, tradeId: string, alloc?: number => { }; + public repersist = (report: T, tradeId: string, alloc?: number) => { }; public loadLatest = (): Q.Promise => { if (this.initialData) diff --git a/src/service/persister.ts b/src/service/persister.ts index 94ac3d17a..83e4377ca 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -54,7 +54,7 @@ export class LoaderSaver { export interface IPersist { persist(data: T): void; perfind(report: T, side: Models.Side, width?: number, price?: number): any; - repersist(data: T): void; + repersist(report: T, tradeId: string, alloc?: number): void; } export interface ILoadLatest extends IPersist { @@ -96,7 +96,7 @@ export class RepositoryPersister implements ILoadLatest { }; - public repersist = (report: T) => { }; + public repersist = (report: T, tradeId: string, alloc?: number) => { }; public persist = (report: T) => { this._saver(report); From 7ce716ed5dbb0cc1f5d2f5a010ad5ad38b9a41e4 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 05:00:12 +0200 Subject: [PATCH 065/202] Added Boomerang calcs. --- src/admin/trades.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 547a70fac..2c461494c 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -32,7 +32,7 @@ class DisplayTrade { this.time = (moment.isMoment(trade.time) ? trade.time : moment(trade.time)); this.price = trade.price; this.quantity = trade.quantity; - this.alloc = 0; + this.alloc = trade.alloc; this.value = trade.value; if (trade.liquidity === 0 || trade.liquidity === 1) { @@ -79,14 +79,15 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri }; var addTrade = t => { + var _t = new DisplayTrade($scope, t); var exists = 0; for(var i = 0;i<$scope.trade_statuses.length;i++) { - if ($scope.trade_statuses.tradeId==t.tradeId) { + if ($scope.trade_statuses.tradeId==_t.tradeId) { exists = 1; - $scope.trade_statuses.alloc = t.alloc; + $scope.trade_statuses.alloc = _t.alloc; } } - if (!exists) $scope.trade_statuses.push(new DisplayTrade($scope, t)); + if (!exists) $scope.trade_statuses.push(_t); if ($scope.sound) { var audio = new Audio('http://antminer/a.mp3'); audio.volume = 0.5; From 3d026c1bd6cf2c3a637a85904f0f4b55cb106739 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 05:02:03 +0200 Subject: [PATCH 066/202] Added Boomerang calcs. --- src/admin/trades.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 2c461494c..e1337b3ed 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -32,7 +32,7 @@ class DisplayTrade { this.time = (moment.isMoment(trade.time) ? trade.time : moment(trade.time)); this.price = trade.price; this.quantity = trade.quantity; - this.alloc = trade.alloc; + this.alloc = alloc; this.value = trade.value; if (trade.liquidity === 0 || trade.liquidity === 1) { @@ -79,15 +79,14 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri }; var addTrade = t => { - var _t = new DisplayTrade($scope, t); var exists = 0; for(var i = 0;i<$scope.trade_statuses.length;i++) { - if ($scope.trade_statuses.tradeId==_t.tradeId) { + if ($scope.trade_statuses[i].tradeId==t.tradeId) { exists = 1; - $scope.trade_statuses.alloc = _t.alloc; + $scope.trade_statuses[i].alloc = t.alloc; } } - if (!exists) $scope.trade_statuses.push(_t); + if (!exists) $scope.trade_statuses.push(new DisplayTrade($scope, t)); if ($scope.sound) { var audio = new Audio('http://antminer/a.mp3'); audio.volume = 0.5; From 0de9409bd79b32fa3bc46f92d4ad61ad2142806e Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 22 Jul 2016 05:02:52 +0200 Subject: [PATCH 067/202] Added Boomerang calcs. --- src/admin/trades.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index e1337b3ed..8fc655256 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -32,7 +32,7 @@ class DisplayTrade { this.time = (moment.isMoment(trade.time) ? trade.time : moment(trade.time)); this.price = trade.price; this.quantity = trade.quantity; - this.alloc = alloc; + this.alloc = trade.alloc; this.value = trade.value; if (trade.liquidity === 0 || trade.liquidity === 1) { From 3f0eaaad5c41a8891db962bd77329dc7cc7205a5 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 23 Jul 2016 19:15:51 +0200 Subject: [PATCH 068/202] Added CAD currency. --- src/common/models.ts | 2 +- src/service/gateways/coinbase.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/common/models.ts b/src/common/models.ts index 5e84ddaaa..82e326854 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -58,7 +58,7 @@ export class MarketTrade implements ITimestamped { } export enum GatewayType { MarketData, OrderEntry, Position } -export enum Currency { USD, BTC, LTC, EUR, GBP, CNY , ETH } +export enum Currency { USD, BTC, LTC, EUR, GBP, CNY , ETH , CAD } export enum ConnectivityStatus { Connected, Disconnected } export enum Exchange { Null, HitBtc, OkCoin, AtlasAts, BtcChina, Coinbase, Bitfinex } export enum Side { Bid, Ask, Unknown } diff --git a/src/service/gateways/coinbase.ts b/src/service/gateways/coinbase.ts index cc5db87e0..715074c51 100644 --- a/src/service/gateways/coinbase.ts +++ b/src/service/gateways/coinbase.ts @@ -797,6 +797,7 @@ function GetCurrencyEnum(name: string): Models.Currency { case "EUR": return Models.Currency.EUR; case "GBP": return Models.Currency.GBP; case "ETH": return Models.Currency.GBP; + case "CAD": return Models.Currency.CAD; default: throw new Error("Unsupported currency " + name); } } @@ -808,6 +809,7 @@ function GetCurrencySymbol(c: Models.Currency): string { case Models.Currency.BTC: return "BTC"; case Models.Currency.EUR: return "EUR"; case Models.Currency.ETH: return "ETH"; + case Models.Currency.CAD: return "CAD"; default: throw new Error("Unsupported currency " + Models.Currency[c]); } } From 8f8367de17dd8db9606b54a6ac3d01f5f4e20d7b Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 23 Jul 2016 21:24:03 +0200 Subject: [PATCH 069/202] Fixed loop. --- src/service/broker.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 949c7ffc8..f4d845c81 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -275,9 +275,12 @@ export class OrderBroker implements Interfaces.IOrderBroker { this._tradePersister.persist(trade); this._trades.push(trade); } else { - while (trade.quantity>0 && reTrade!=null && reTrade) { + var gowhile = true; + while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { + gowhile = false; for(var i = 0;i Date: Sat, 23 Jul 2016 22:26:45 +0200 Subject: [PATCH 070/202] Fixed side. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 83e4377ca..f4b4ee981 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -180,7 +180,7 @@ export class Persister implements ILoadAll { this.collection.then(coll => { coll.find({ $and: [ { price: side==Models.Side.Bid?{ $gt: width+price }:{ $lt: price-width } }, - { side: side==Models.Side.Bid?Models.Side.Ask:Models.Side.Bid }, + { side: side==Models.Side.Bid?1:0 }, { $where: "this.quantity - this.alloc > 0" } ] }).limit(1).sort({ alloc: 1, price: side==Models.Side.Bid?-1:1 }) .toArray((err, arr) => { From c5a3f7554dd64cc3e5fe68b8312e3587b8b0d7ad Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 02:00:50 +0200 Subject: [PATCH 071/202] Fixed calcs. --- src/service/safety.ts | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index 82f0faebf..a6329c5aa 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -81,18 +81,24 @@ export class SafetyCalculator { var sellPq = 0; var _buyPq = 0; var _sellPq = 0; - for (var ti = (settings.mode === Models.QuotingMode.Boomerang?0:this._broker._trades.length - 1); (settings.mode === Models.QuotingMode.Boomerang?ti -1); (settings.mode === Models.QuotingMode.Boomerang?ti++:ti--)) { - if ((settings.mode !== Models.QuotingMode.Boomerang || this._broker._trades[ti].allocb.price;}); + for (var ti = 0;ti=settings.size) break; + } + trades.sort(function(a,b){return a.price=settings.size && sellPq>=settings.size) break; + if (sellPq>=settings.size) break; } if (buyPq) buyPing /= buyPq; From e98634638971cecfdc4113cf4d1a082e9c451874 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 02:05:57 +0200 Subject: [PATCH 072/202] Fixed calcs. --- src/service/safety.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index a6329c5aa..93968e46e 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -82,7 +82,7 @@ export class SafetyCalculator { var _buyPq = 0; var _sellPq = 0; var trades = this._broker._trades; - trades.sort(function(a,b){return a.price>b.price;}); + trades.sort(function(a,b){return a.price>b.price?1:(a.price=settings.size) break; } - trades.sort(function(a,b){return a.priceb.price?-1:0);}); for (var ti = 0;ti Date: Sun, 24 Jul 2016 02:12:27 +0200 Subject: [PATCH 073/202] Fixed calcs. --- src/service/broker.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/service/broker.ts b/src/service/broker.ts index f4d845c81..cafa7ebc8 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -270,6 +270,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, feeCharged); this.Trade.trigger(trade); var reTrade = this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price); + console.log('reTrade',reTrade, 'trade',trade, 'side',trade.side, 'width',this._qlParamRepo.latest.width, 'price',trade.price); if (reTrade==null||!reTrade) { this._tradePublisher.publish(trade); this._tradePersister.persist(trade); From 750d1a26eb086891ae40c2dad14a49e7e07637ea Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 02:14:59 +0200 Subject: [PATCH 074/202] Fixed calcs. --- src/service/broker.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/service/broker.ts b/src/service/broker.ts index cafa7ebc8..156bb6e25 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -272,15 +272,20 @@ export class OrderBroker implements Interfaces.IOrderBroker { var reTrade = this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price); console.log('reTrade',reTrade, 'trade',trade, 'side',trade.side, 'width',this._qlParamRepo.latest.width, 'price',trade.price); if (reTrade==null||!reTrade) { + console.log('reTrade-nope'); this._tradePublisher.publish(trade); this._tradePersister.persist(trade); this._trades.push(trade); } else { + console.log('reTrade-maybe'); var gowhile = true; while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { + console.log('reTrade-almost'); gowhile = false; for(var i = 0;i Date: Sun, 24 Jul 2016 02:34:56 +0200 Subject: [PATCH 075/202] Fixed calcs. --- src/service/persister.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/service/persister.ts b/src/service/persister.ts index f4b4ee981..90bdbeec2 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -177,6 +177,7 @@ export class Persister implements ILoadAll { public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { var deferred = Q.defer(); + console.log('prefind'); this.collection.then(coll => { coll.find({ $and: [ { price: side==Models.Side.Bid?{ $gt: width+price }:{ $lt: price-width } }, @@ -185,12 +186,15 @@ export class Persister implements ILoadAll { ] }).limit(1).sort({ alloc: 1, price: side==Models.Side.Bid?-1:1 }) .toArray((err, arr) => { if (err) { + console.log('prefind-err'); deferred.reject(err); } else if (arr.length === 0) { + console.log('prefind-0'); deferred.resolve(null); } else { + console.log('prefind-1'); this._loader(arr[0]); deferred.resolve(arr[0]); } From c8ed754a9c0fb43a200951a63814cebd76fbebd8 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 02:43:20 +0200 Subject: [PATCH 076/202] Fixed calcs. --- src/service/broker.ts | 12 ++++++------ src/service/persister.ts | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 156bb6e25..500674b89 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -270,22 +270,22 @@ export class OrderBroker implements Interfaces.IOrderBroker { o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, feeCharged); this.Trade.trigger(trade); var reTrade = this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price); - console.log('reTrade',reTrade, 'trade',trade, 'side',trade.side, 'width',this._qlParamRepo.latest.width, 'price',trade.price); + this._log.info('reTrade'+' '+reTrade+' '+'trade'+' '+trade+' '+'side'+' '+trade.side+' '+width+' '+this._qlParamRepo.latest.width+' '+'price'+' '+trade.price); if (reTrade==null||!reTrade) { - console.log('reTrade-nope'); + this._log.info('reTrade-nope'); this._tradePublisher.publish(trade); this._tradePersister.persist(trade); this._trades.push(trade); } else { - console.log('reTrade-maybe'); + this._log.info('reTrade-maybe'); var gowhile = true; while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { - console.log('reTrade-almost'); + this._log.info('reTrade-almost'); gowhile = false; for(var i = 0;i implements ILoadAll { public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { var deferred = Q.defer(); - console.log('prefind'); + this._log.info('prefind'); this.collection.then(coll => { coll.find({ $and: [ { price: side==Models.Side.Bid?{ $gt: width+price }:{ $lt: price-width } }, @@ -186,15 +186,15 @@ export class Persister implements ILoadAll { ] }).limit(1).sort({ alloc: 1, price: side==Models.Side.Bid?-1:1 }) .toArray((err, arr) => { if (err) { - console.log('prefind-err'); + this._log.info('prefind-err'); deferred.reject(err); } else if (arr.length === 0) { - console.log('prefind-0'); + this._log.info('prefind-0'); deferred.resolve(null); } else { - console.log('prefind-1'); + this._log.info('prefind-1'); this._loader(arr[0]); deferred.resolve(arr[0]); } From 1cf9aeaefe17108681f0047c2428644b049c040e Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 02:44:17 +0200 Subject: [PATCH 077/202] Fixed calcs. --- src/service/broker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 500674b89..b68d1b068 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -270,7 +270,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, feeCharged); this.Trade.trigger(trade); var reTrade = this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price); - this._log.info('reTrade'+' '+reTrade+' '+'trade'+' '+trade+' '+'side'+' '+trade.side+' '+width+' '+this._qlParamRepo.latest.width+' '+'price'+' '+trade.price); + this._log.info('reTrade'+' '+reTrade+' '+'trade'+' '+trade+' '+'side'+' '+trade.side+' '+'width'+' '+this._qlParamRepo.latest.width+' '+'price'+' '+trade.price); if (reTrade==null||!reTrade) { this._log.info('reTrade-nope'); this._tradePublisher.publish(trade); From ff6784840c2422cdacc9a479e56d77eae620cd44 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 02:58:05 +0200 Subject: [PATCH 078/202] Fixed calcs. --- src/service/broker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index b68d1b068..f96edbc2b 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -152,7 +152,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { // race condition! i cannot cancel an order before I get the exchangeId (oid); register it for deletion on the ack if (typeof rpt.exchangeId === "undefined") { this._cancelsWaitingForExchangeOrderId[rpt.orderId] = cancel; - this._log.info("Registered %s for late deletion", rpt.orderId); + /////this._log.info("Registered %s for late deletion", rpt.orderId); return; } } @@ -243,7 +243,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { if (!this._oeGateway.cancelsByClientOrderId && typeof o.exchangeId !== "undefined" && o.orderId in this._cancelsWaitingForExchangeOrderId) { - this._log.info("Deleting %s late, oid: %s", o.exchangeId, o.orderId); + /////this._log.info("Deleting %s late, oid: %s", o.exchangeId, o.orderId); var cancel = this._cancelsWaitingForExchangeOrderId[o.orderId]; delete this._cancelsWaitingForExchangeOrderId[o.orderId]; this.cancelOrder(cancel); From 15be4680a9dcea751045e87232f5b2dd8a5520d0 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 03:14:48 +0200 Subject: [PATCH 079/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 0dce579a1..8dc1a3b3a 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -176,7 +176,7 @@ export class Persister implements ILoadAll { }; public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { - var deferred = Q.defer(); + var deferred = Q.defer(); this._log.info('prefind'); this.collection.then(coll => { coll.find({ $and: [ From f3dbdac284746bfdba5d5b2db257987588d7e5c2 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 03:34:55 +0200 Subject: [PATCH 080/202] Fixed calcs. --- src/service/broker.ts | 62 ++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index f96edbc2b..24becc2b7 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -269,40 +269,42 @@ export class OrderBroker implements Interfaces.IOrderBroker { const trade = new Models.Trade(o.orderId+"."+o.version, o.time, o.exchange, o.pair, o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, feeCharged); this.Trade.trigger(trade); - var reTrade = this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price); - this._log.info('reTrade'+' '+reTrade+' '+'trade'+' '+trade+' '+'side'+' '+trade.side+' '+'width'+' '+this._qlParamRepo.latest.width+' '+'price'+' '+trade.price); - if (reTrade==null||!reTrade) { - this._log.info('reTrade-nope'); - this._tradePublisher.publish(trade); - this._tradePersister.persist(trade); - this._trades.push(trade); - } else { - this._log.info('reTrade-maybe'); - var gowhile = true; - while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { - this._log.info('reTrade-almost'); - gowhile = false; - for(var i = 0;i0) reTrade = this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price); - break; - } - } - } - if (trade.quantity>0) { + this._log.info('reTrade-init'); + var function _reTrade(reTrade) { + if (reTrade==null||!reTrade) { + this._log.info('reTrade-nope'); this._tradePublisher.publish(trade); this._tradePersister.persist(trade); this._trades.push(trade); + } else { + this._log.info('reTrade-maybe'); + var gowhile = true; + while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { + this._log.info('reTrade-almost'); + gowhile = false; + for(var i = 0;i0) this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { _reTrade(reTrade); }); + break; + } + } + } + if (trade.quantity>0) { + this._tradePublisher.publish(trade); + this._tradePersister.persist(trade); + this._trades.push(trade); + } } - } + }; + this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { _reTrade(reTrade); }); } }; From 3cccc2473707da31cda2e666fdaf9fad40ed1987 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 03:35:31 +0200 Subject: [PATCH 081/202] Fixed calcs. --- src/service/broker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 24becc2b7..33f1868b2 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -270,7 +270,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, feeCharged); this.Trade.trigger(trade); this._log.info('reTrade-init'); - var function _reTrade(reTrade) { + var _reTrade = function (reTrade) { if (reTrade==null||!reTrade) { this._log.info('reTrade-nope'); this._tradePublisher.publish(trade); From 9afa850c71bbabfeaf439e2c105beac12d615810 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 03:59:51 +0200 Subject: [PATCH 082/202] Fixed calcs. --- src/service/main.ts | 3 +-- src/service/statistics.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/service/main.ts b/src/service/main.ts index 240771a5a..3df31998e 100644 --- a/src/service/main.ts +++ b/src/service/main.ts @@ -415,8 +415,7 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { var delta = process.hrtime(start); var ms = (delta[0] * 1e9 + delta[1]) / 1e6; var n = ms - interval; - if (n > 25) - mainLog.info("Event looped blocked for " + Utils.roundFloat(n) + "ms"); + ////if (n > 25) mainLog.info("Event looped blocked for " + Utils.roundFloat(n) + "ms"); start = process.hrtime(); }, interval).unref(); diff --git a/src/service/statistics.ts b/src/service/statistics.ts index 76ef961a3..969b24482 100644 --- a/src/service/statistics.ts +++ b/src/service/statistics.ts @@ -72,7 +72,7 @@ export class ObservableEWMACalculator implements Interfaces.IEwmaCalculator { this._latest = v; this.Updated.trigger(); - this._log.info("New EMWA value", this._latest); + ////this._log.info("New EMWA value", this._latest); } }; From 6471897d705fa19acb326cd771fada6e02470ed5 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 04:45:22 +0200 Subject: [PATCH 083/202] Fixed loop. --- src/service/main.ts | 5 +++-- src/service/safety.ts | 12 ++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/service/main.ts b/src/service/main.ts index 3df31998e..167ceae54 100644 --- a/src/service/main.ts +++ b/src/service/main.ts @@ -329,14 +329,15 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { var marketDataBroker = new Broker.MarketDataBroker(gateway.md, marketDataPublisher, marketDataPersister, messages); var positionBroker = new Broker.PositionBroker(timeProvider, broker, gateway.pg, positionPublisher, positionPersister, marketDataBroker); - var safetyCalculator = new Safety.SafetyCalculator(timeProvider, paramsRepo, orderBroker, paramsRepo, tradeSafetyPublisher, tsvPersister); - var startQuoting = (timeProvider.utcNow().diff(initActive.time, 'minutes') < 3 && initActive.active); var active = new Active.ActiveRepository(startQuoting, broker, activePublisher, activeReceiver); var quoter = new Quoter.Quoter(orderBroker, broker); var filtration = new MarketFiltration.MarketFiltration(quoter, marketDataBroker); var fvEngine = new FairValue.FairValueEngine(timeProvider, filtration, paramsRepo, fvPublisher, fairValuePersister); + + var safetyCalculator = new Safety.SafetyCalculator(timeProvider, fvEngine, paramsRepo, orderBroker, paramsRepo, tradeSafetyPublisher, tsvPersister); + var ewma = new Statistics.ObservableEWMACalculator(timeProvider, fvEngine, initParams.quotingEwma); var rfvValues = _.map(initRfv, (r: Models.RegularFairValue) => r.value); diff --git a/src/service/safety.ts b/src/service/safety.ts index 93968e46e..96e47083d 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -14,6 +14,7 @@ import Broker = require("./broker"); import Messaging = require("../common/messaging"); import moment = require('moment'); import _ = require("lodash"); +import FairValue = require("./fair-value"); import Persister = require("./persister"); export class SafetyCalculator { @@ -40,6 +41,7 @@ export class SafetyCalculator { constructor( private _timeProvider: Utils.ITimeProvider, + private _fvEngine: FairValue.FairValueEngine, private _repo: Interfaces.IRepository, private _broker: Broker.OrderBroker, private _qlParams: Interfaces.IRepository, @@ -82,18 +84,20 @@ export class SafetyCalculator { var _buyPq = 0; var _sellPq = 0; var trades = this._broker._trades; - trades.sort(function(a,b){return a.price>b.price?1:(a.priceb.price?-1:0);}); for (var ti = 0;titrades[ti].price) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].alloc=settings.size) break; } - trades.sort(function(a,b){return a.priceb.price?-1:0);}); + trades.sort(function(a,b){return a.price>b.price?1:(a.price Date: Sun, 24 Jul 2016 04:47:15 +0200 Subject: [PATCH 084/202] Fixed calcs. --- src/service/safety.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index 96e47083d..4d488a5a5 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -84,11 +84,12 @@ export class SafetyCalculator { var _buyPq = 0; var _sellPq = 0; var trades = this._broker._trades; - var fv = this._fvEngine.latestFairValue - if (fv != null) {fv = fv.price;} else fv = 0; + var fv = this._fvEngine.latestFairValue; + var fvp = 0; + if (fv != null) {fvp = fv.price;} trades.sort(function(a,b){return a.priceb.price?-1:0);}); for (var ti = 0;titrades[ti].price) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].alloctrades[ti].price) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].allocb.price?1:(a.price Date: Sun, 24 Jul 2016 04:57:33 +0200 Subject: [PATCH 085/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 8dc1a3b3a..efbb5ce82 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -183,7 +183,7 @@ export class Persister implements ILoadAll { { price: side==Models.Side.Bid?{ $gt: width+price }:{ $lt: price-width } }, { side: side==Models.Side.Bid?1:0 }, { $where: "this.quantity - this.alloc > 0" } - ] }).limit(1).sort({ alloc: 1, price: side==Models.Side.Bid?-1:1 }) + ] }).limit(1).sort({ alloc: 1, price: side==Models.Side.Bid?1:-1 }) .toArray((err, arr) => { if (err) { this._log.info('prefind-err'); From dcd12edef927c85c4b64e32002ac519f8739ed51 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 11:25:48 +0200 Subject: [PATCH 086/202] Fixed calcs. --- src/service/broker.ts | 71 ++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 33f1868b2..fa5fa79d2 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -169,6 +169,41 @@ export class OrderBroker implements Interfaces.IOrderBroker { this.onOrderUpdate(rpt); }; + private _reTrade = (reTrade: Models.Timestamped) => { + if (reTrade==null||!reTrade) { + this._log.info('reTrade-nope'); + this._tradePublisher.publish(trade); + this._tradePersister.persist(trade); + this._trades.push(trade); + } else { + this._log.info('reTrade-maybe'); + var gowhile = true; + while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { + this._log.info('reTrade-almost'); + gowhile = false; + for(var i = 0;i0) this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(this._reTrade); + break; + } + } + } + if (trade.quantity>0) { + this._tradePublisher.publish(trade); + this._tradePersister.persist(trade); + this._trades.push(trade); + } + } + }; + public onOrderUpdate = (osr : Models.OrderStatusReport) => { var orig : Models.OrderStatusReport; if (osr.orderStatus === Models.OrderStatus.New) { @@ -270,41 +305,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, feeCharged); this.Trade.trigger(trade); this._log.info('reTrade-init'); - var _reTrade = function (reTrade) { - if (reTrade==null||!reTrade) { - this._log.info('reTrade-nope'); - this._tradePublisher.publish(trade); - this._tradePersister.persist(trade); - this._trades.push(trade); - } else { - this._log.info('reTrade-maybe'); - var gowhile = true; - while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { - this._log.info('reTrade-almost'); - gowhile = false; - for(var i = 0;i0) this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { _reTrade(reTrade); }); - break; - } - } - } - if (trade.quantity>0) { - this._tradePublisher.publish(trade); - this._tradePersister.persist(trade); - this._trades.push(trade); - } - } - }; - this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { _reTrade(reTrade); }); + this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(this._reTrade}); } }; From f4d8df8666733c59864b1ea4d5778447e31731b7 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 11:27:47 +0200 Subject: [PATCH 087/202] Fixed calcs. --- src/service/broker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index fa5fa79d2..708e9d302 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -305,7 +305,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, feeCharged); this.Trade.trigger(trade); this._log.info('reTrade-init'); - this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(this._reTrade}); + this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(this._reTrade); } }; From b6d75c76e951b7a8eb85f2ba5518a4eb3ed448a8 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 11:39:54 +0200 Subject: [PATCH 088/202] Fixed calcs. --- src/service/broker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 708e9d302..4d287ddb4 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -169,7 +169,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { this.onOrderUpdate(rpt); }; - private _reTrade = (reTrade: Models.Timestamped) => { + private _reTrade = (reTrade: Models.Timestamped, trade: Models.Trade) => { if (reTrade==null||!reTrade) { this._log.info('reTrade-nope'); this._tradePublisher.publish(trade); @@ -191,7 +191,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { trade.quantity -= allocMod; this._tradePublisher.publish(this._trades[i]); this._tradePersister.repersist(this._trades[i], this._trades[i].tradeId, this._trades[i].alloc); - if (trade.quantity>0) this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(this._reTrade); + if (trade.quantity>0) this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { this._reTrade(reTrade, trade); }); break; } } @@ -305,7 +305,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, feeCharged); this.Trade.trigger(trade); this._log.info('reTrade-init'); - this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(this._reTrade); + this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { this._reTrade(reTrade, trade); }); } }; From 446d2d8712653eab91fe55d371d4fe0e4ccb9687 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 11:40:49 +0200 Subject: [PATCH 089/202] Fixed calcs. --- src/service/broker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 4d287ddb4..9b37e53d3 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -169,7 +169,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { this.onOrderUpdate(rpt); }; - private _reTrade = (reTrade: Models.Timestamped, trade: Models.Trade) => { + private _reTrade = (reTrade: Models.Trade, trade: Models.Trade) => { if (reTrade==null||!reTrade) { this._log.info('reTrade-nope'); this._tradePublisher.publish(trade); From 7cb64a19a23dc96087ac17befe40e13fb442ba0c Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 11:48:50 +0200 Subject: [PATCH 090/202] Fixed calcs. --- src/service/broker.ts | 6 ------ src/service/persister.ts | 4 ---- 2 files changed, 10 deletions(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 9b37e53d3..2e9e1d945 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -171,20 +171,15 @@ export class OrderBroker implements Interfaces.IOrderBroker { private _reTrade = (reTrade: Models.Trade, trade: Models.Trade) => { if (reTrade==null||!reTrade) { - this._log.info('reTrade-nope'); this._tradePublisher.publish(trade); this._tradePersister.persist(trade); this._trades.push(trade); } else { - this._log.info('reTrade-maybe'); var gowhile = true; while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { - this._log.info('reTrade-almost'); gowhile = false; for(var i = 0;i { this._reTrade(reTrade, trade); }); } }; diff --git a/src/service/persister.ts b/src/service/persister.ts index efbb5ce82..dc3d87bb0 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -177,7 +177,6 @@ export class Persister implements ILoadAll { public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { var deferred = Q.defer(); - this._log.info('prefind'); this.collection.then(coll => { coll.find({ $and: [ { price: side==Models.Side.Bid?{ $gt: width+price }:{ $lt: price-width } }, @@ -186,15 +185,12 @@ export class Persister implements ILoadAll { ] }).limit(1).sort({ alloc: 1, price: side==Models.Side.Bid?1:-1 }) .toArray((err, arr) => { if (err) { - this._log.info('prefind-err'); deferred.reject(err); } else if (arr.length === 0) { - this._log.info('prefind-0'); deferred.resolve(null); } else { - this._log.info('prefind-1'); this._loader(arr[0]); deferred.resolve(arr[0]); } From 4b95bc600c8a79880e094d4335a0b5e8c700e175 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 12:06:38 +0200 Subject: [PATCH 091/202] Fixed calcs. --- src/admin/trades.ts | 6 +++++- src/common/models.ts | 1 + src/service/broker.ts | 42 ++++++++++++++++++------------------------ src/service/safety.ts | 16 ++++++++++++++++ 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 8fc655256..cec73d43c 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -25,6 +25,7 @@ class DisplayTrade { value : number; liquidity : string; alloc : number; + allocprice : number; constructor($scope : TradesScope, public trade : Models.Trade) { this.tradeId = trade.tradeId; @@ -34,6 +35,7 @@ class DisplayTrade { this.quantity = trade.quantity; this.alloc = trade.alloc; this.value = trade.value; + this.allocprice = trade.allocprice; if (trade.liquidity === 0 || trade.liquidity === 1) { this.liquidity = Models.Liquidity[trade.liquidity].charAt(0); @@ -74,7 +76,8 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri }}, {width: 30, field:'liquidity', displayName:'liq'}, {width: 60, field:'value', displayName:'val', cellFilter: 'currency:"$":3'}, - {width: 50, field:'alloc', displayName:'alloc'} + {width: 50, field:'alloc', displayName:'alloc'}, + {width: 55, field:'allocprice', displayName:'px', cellFilter: 'currency'} ] }; @@ -84,6 +87,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri if ($scope.trade_statuses[i].tradeId==t.tradeId) { exists = 1; $scope.trade_statuses[i].alloc = t.alloc; + $scope.trade_statuses[i].allocprice = t.allocprice; } } if (!exists) $scope.trade_statuses.push(new DisplayTrade($scope, t)); diff --git a/src/common/models.ts b/src/common/models.ts index 82e326854..9d6c69d3b 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -251,6 +251,7 @@ export class Trade implements ITimestamped { public value: number, public liquidity: Liquidity, public alloc: number, + public allocprice: number, public feeCharged: number) {} } diff --git a/src/service/broker.ts b/src/service/broker.ts index 2e9e1d945..1e928777c 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -170,32 +170,26 @@ export class OrderBroker implements Interfaces.IOrderBroker { }; private _reTrade = (reTrade: Models.Trade, trade: Models.Trade) => { - if (reTrade==null||!reTrade) { + var gowhile = true; + while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { + gowhile = false; + for(var i = 0;i0) this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { this._reTrade(reTrade, trade); }); + break; + } + } + } + if (trade.quantity>0) { this._tradePublisher.publish(trade); this._tradePersister.persist(trade); this._trades.push(trade); - } else { - var gowhile = true; - while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { - gowhile = false; - for(var i = 0;i0) this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { this._reTrade(reTrade, trade); }); - break; - } - } - } - if (trade.quantity>0) { - this._tradePublisher.publish(trade); - this._tradePersister.persist(trade); - this._trades.push(trade); - } } }; @@ -297,7 +291,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { } const trade = new Models.Trade(o.orderId+"."+o.version, o.time, o.exchange, o.pair, - o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, feeCharged); + o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, 0, feeCharged); this.Trade.trigger(trade); this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { this._reTrade(reTrade, trade); }); } diff --git a/src/service/safety.ts b/src/service/safety.ts index 4d488a5a5..b7e77e4d8 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -89,6 +89,14 @@ export class SafetyCalculator { if (fv != null) {fvp = fv.price;} trades.sort(function(a,b){return a.priceb.price?-1:0);}); for (var ti = 0;titrades[ti].price && fvp-settings.width=settings.size) break; + } + if (!buyPq) for (var ti = 0;titrades[ti].price) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].allocb.price?1:(a.pricetrades[ti].price)) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].alloc=settings.size) break; + } + if (!sellPq) for (var ti = 0;ti Date: Sun, 24 Jul 2016 12:09:46 +0200 Subject: [PATCH 092/202] Fixed calcs. --- src/service/broker.ts | 2 +- src/service/safety.ts | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 1e928777c..f521c3878 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -172,7 +172,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { private _reTrade = (reTrade: Models.Trade, trade: Models.Trade) => { var gowhile = true; while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { - gowhile = false; + gowhile = false;//allocprice for(var i = 0;ib.price?-1:0);}); + trades.sort(function(a,b){return a.price>b.price?1:(a.pricetrades[ti].price && fvp-settings.width=settings.size) break; } + trades.sort(function(a,b){return a.priceb.price?-1:0);}); if (!buyPq) for (var ti = 0;titrades[ti].price) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].alloc=settings.size) break; } - trades.sort(function(a,b){return a.price>b.price?1:(a.priceb.price?-1:0);}); for (var ti = 0;titrades[ti].price)) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].alloc=settings.size) break; } + trades.sort(function(a,b){return a.price>b.price?1:(a.price Date: Sun, 24 Jul 2016 12:44:47 +0200 Subject: [PATCH 093/202] Fixed calcs. --- src/service/broker.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index f521c3878..4b41fec83 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -172,13 +172,14 @@ export class OrderBroker implements Interfaces.IOrderBroker { private _reTrade = (reTrade: Models.Trade, trade: Models.Trade) => { var gowhile = true; while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { - gowhile = false;//allocprice + gowhile = false; for(var i = 0;i0) this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { this._reTrade(reTrade, trade); }); From fe46716a02c3bfa74ef58b80197ca79984d46bb0 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 12:53:27 +0200 Subject: [PATCH 094/202] Fixed calcs. --- src/service/broker.ts | 2 +- src/service/persister.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 4b41fec83..2e1297c26 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -181,7 +181,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { this._trades[i].alloc += allocQty; trade.quantity -= allocQty; this._tradePublisher.publish(this._trades[i]); - this._tradePersister.repersist(this._trades[i], this._trades[i].tradeId, this._trades[i].alloc); + this._tradePersister.repersist(this._trades[i], this._trades[i].tradeId, this._trades[i].alloc, this._trades[i].allocprice); if (trade.quantity>0) this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { this._reTrade(reTrade, trade); }); break; } diff --git a/src/service/persister.ts b/src/service/persister.ts index dc3d87bb0..bfac2d131 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -200,10 +200,10 @@ export class Persister implements ILoadAll { return deferred.promise; }; - public repersist = (report: T, tradeId: string, alloc?: number) => { + public repersist = (report: T, tradeId: string, alloc?: number, allocprice?: number) => { this.collection.then(coll => { this._saver(report); - coll.findOneAndUpdate({ tradeId: tradeId }, { alloc : alloc }, err => { + coll.findOneAndUpdate({ tradeId: tradeId }, { alloc : alloc, allocprice : allocprice }, err => { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); From f04aa8414902bf95cd04ad213ca373e84db07b78 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 12:57:46 +0200 Subject: [PATCH 095/202] Fixed calcs. --- src/service/backtest.ts | 2 +- src/service/persister.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/service/backtest.ts b/src/service/backtest.ts index 976c7eb0b..f78411eb9 100644 --- a/src/service/backtest.ts +++ b/src/service/backtest.ts @@ -312,7 +312,7 @@ export class BacktestPersister implements Persister.ILoadAll, Persister.IL public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { }; - public repersist = (report: T, tradeId: string, alloc?: number) => { }; + public repersist = (report: T, tradeId: string, alloc?: number, _allocprice?: number) => { }; public loadLatest = (): Q.Promise => { if (this.initialData) diff --git a/src/service/persister.ts b/src/service/persister.ts index bfac2d131..4d520bb61 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -54,7 +54,7 @@ export class LoaderSaver { export interface IPersist { persist(data: T): void; perfind(report: T, side: Models.Side, width?: number, price?: number): any; - repersist(report: T, tradeId: string, alloc?: number): void; + repersist(report: T, tradeId: string, alloc?: number, _allocprice?: number): void; } export interface ILoadLatest extends IPersist { @@ -96,7 +96,7 @@ export class RepositoryPersister implements ILoadLatest { }; - public repersist = (report: T, tradeId: string, alloc?: number) => { }; + public repersist = (report: T, tradeId: string, alloc?: number, _allocprice?: number) => { }; public persist = (report: T) => { this._saver(report); @@ -200,10 +200,10 @@ export class Persister implements ILoadAll { return deferred.promise; }; - public repersist = (report: T, tradeId: string, alloc?: number, allocprice?: number) => { + public repersist = (report: T, _tradeId: string, _alloc?: number, _allocprice?: number) => { this.collection.then(coll => { this._saver(report); - coll.findOneAndUpdate({ tradeId: tradeId }, { alloc : alloc, allocprice : allocprice }, err => { + coll.updateOne({ tradeId: _tradeId }, { alloc : _alloc, allocprice : _allocprice }, err => { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); From 417c39ef0091485dc8a724414bdce3e21bac4f94 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 13:00:14 +0200 Subject: [PATCH 096/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 4d520bb61..2a55976eb 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -203,7 +203,7 @@ export class Persister implements ILoadAll { public repersist = (report: T, _tradeId: string, _alloc?: number, _allocprice?: number) => { this.collection.then(coll => { this._saver(report); - coll.updateOne({ tradeId: _tradeId }, { alloc : _alloc, allocprice : _allocprice }, err => { + coll.updateOne({ tradeId: _tradeId }, { $set: { alloc : _alloc, allocprice : _allocprice } }, err => { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); From e764957ec32a5c2bebd15674064351970e34a534 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 13:03:16 +0200 Subject: [PATCH 097/202] Fixed calcs. --- src/admin/trades.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index cec73d43c..c048c0bc2 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -58,7 +58,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri rowHeight: 20, headerRowHeight: 20, columnDefs: [ - {width: 80, field:'time', displayName:'t', cellFilter: 'momentShortDate', + {width: 65, field:'time', displayName:'t', cellFilter: 'momentShortDate', sortingAlgorithm: (a: moment.Moment, b: moment.Moment) => a.diff(b), sort: { direction: uiGridConstants.DESC, priority: 1} }, {width: 55, field:'price', displayName:'px', cellFilter: 'currency'}, From ca4a14a0731a4bc69c385b1e713548723633dd12 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 13:06:21 +0200 Subject: [PATCH 098/202] Fixed calcs. --- src/admin/trades.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index c048c0bc2..4e47da89d 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -61,9 +61,9 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri {width: 65, field:'time', displayName:'t', cellFilter: 'momentShortDate', sortingAlgorithm: (a: moment.Moment, b: moment.Moment) => a.diff(b), sort: { direction: uiGridConstants.DESC, priority: 1} }, - {width: 55, field:'price', displayName:'px', cellFilter: 'currency'}, + {width: 50, field:'price', displayName:'px', cellFilter: 'currency'}, {width: 50, field:'quantity', displayName:'qty'}, - {width: 30, field:'side', displayName:'side', cellClass: (grid, row, col, rowRenderIndex, colRenderIndex) => { + {width: 20, field:'side', displayName:'side', cellClass: (grid, row, col, rowRenderIndex, colRenderIndex) => { if (grid.getCellValue(row, col) === 'B') { return 'buy'; } @@ -74,7 +74,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri return "unknown"; } }}, - {width: 30, field:'liquidity', displayName:'liq'}, + {width: 20, field:'liquidity', displayName:'liq'}, {width: 60, field:'value', displayName:'val', cellFilter: 'currency:"$":3'}, {width: 50, field:'alloc', displayName:'alloc'}, {width: 55, field:'allocprice', displayName:'px', cellFilter: 'currency'} From 7a212f8f6d550d1e88503f4716d930502a9f102d Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 13:18:09 +0200 Subject: [PATCH 099/202] Fixed calcs. --- src/admin/trades.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 4e47da89d..79eb5c30e 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -74,7 +74,6 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri return "unknown"; } }}, - {width: 20, field:'liquidity', displayName:'liq'}, {width: 60, field:'value', displayName:'val', cellFilter: 'currency:"$":3'}, {width: 50, field:'alloc', displayName:'alloc'}, {width: 55, field:'allocprice', displayName:'px', cellFilter: 'currency'} From 61bdaaa9e3d74193180f75ed9bfe074da7c057f0 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 13:18:48 +0200 Subject: [PATCH 100/202] Fixed calcs. --- src/admin/trades.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 79eb5c30e..70fcaffc6 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -58,7 +58,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri rowHeight: 20, headerRowHeight: 20, columnDefs: [ - {width: 65, field:'time', displayName:'t', cellFilter: 'momentShortDate', + {width: 70, field:'time', displayName:'t', cellFilter: 'momentShortDate', sortingAlgorithm: (a: moment.Moment, b: moment.Moment) => a.diff(b), sort: { direction: uiGridConstants.DESC, priority: 1} }, {width: 50, field:'price', displayName:'px', cellFilter: 'currency'}, From 75c711b83c7e6cfd10025cda54b807d6af1d8402 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 13:19:35 +0200 Subject: [PATCH 101/202] Fixed calcs. --- src/admin/trades.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 70fcaffc6..df25e3a5f 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -58,7 +58,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri rowHeight: 20, headerRowHeight: 20, columnDefs: [ - {width: 70, field:'time', displayName:'t', cellFilter: 'momentShortDate', + {width: 75, field:'time', displayName:'t', cellFilter: 'momentShortDate', sortingAlgorithm: (a: moment.Moment, b: moment.Moment) => a.diff(b), sort: { direction: uiGridConstants.DESC, priority: 1} }, {width: 50, field:'price', displayName:'px', cellFilter: 'currency'}, From b51a4b58526218c980804f119dd286963995759a Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 13:47:11 +0200 Subject: [PATCH 102/202] Fixed calcs. --- src/admin/trades.ts | 4 ++++ src/service/persister.ts | 1 + 2 files changed, 5 insertions(+) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index df25e3a5f..c2f258b49 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -82,14 +82,18 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri var addTrade = t => { var exists = 0; + var unset = -1; for(var i = 0;i<$scope.trade_statuses.length;i++) { if ($scope.trade_statuses[i].tradeId==t.tradeId) { exists = 1; $scope.trade_statuses[i].alloc = t.alloc; $scope.trade_statuses[i].allocprice = t.allocprice; + if ($scope.trade_statuses[i].alloc>=$scope.trade_statuses[i].quantity) + unset = i; } } if (!exists) $scope.trade_statuses.push(new DisplayTrade($scope, t)); + else if (unset>-1) $scope.trade_statuses[i].splice(unset, 1); if ($scope.sound) { var audio = new Audio('http://antminer/a.mp3'); audio.volume = 0.5; diff --git a/src/service/persister.ts b/src/service/persister.ts index 2a55976eb..fdf895db5 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -207,6 +207,7 @@ export class Persister implements ILoadAll { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); + coll.delete({ $where: "this.alloc >= this.quantity" }); }).done(); }; From 08f06f8f6b5dbbf8a6db3b0c90de5d74a9a376e1 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 13:49:14 +0200 Subject: [PATCH 103/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index fdf895db5..537336c11 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -207,7 +207,7 @@ export class Persister implements ILoadAll { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); - coll.delete({ $where: "this.alloc >= this.quantity" }); + coll.remove({ $where: "this.alloc >= this.quantity" }); }).done(); }; From 3dca3f047f91bd24be84d69fbd96014b5862022f Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 13:55:00 +0200 Subject: [PATCH 104/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 537336c11..82b897f7a 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -207,7 +207,7 @@ export class Persister implements ILoadAll { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); - coll.remove({ $where: "this.alloc >= this.quantity" }); + coll.deleteMany({ $where: "this.alloc >= this.quantity" }); }).done(); }; From 5d4934a38e1697de365c67cf620559fb3ed64b22 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 13:56:03 +0200 Subject: [PATCH 105/202] Fixed calcs. --- src/admin/trades.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index c2f258b49..36c7450ea 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -93,7 +93,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri } } if (!exists) $scope.trade_statuses.push(new DisplayTrade($scope, t)); - else if (unset>-1) $scope.trade_statuses[i].splice(unset, 1); + else if (unset>-1) $scope.trade_statuses.splice(unset, 1); if ($scope.sound) { var audio = new Audio('http://antminer/a.mp3'); audio.volume = 0.5; From d3ca3f8d950d057c5a56808fc63fad6c573f8c1c Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 14:02:53 +0200 Subject: [PATCH 106/202] Fixed calcs. --- src/service/persister.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 82b897f7a..b8e94dc06 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -128,9 +128,9 @@ export class Persister implements ILoadAll { public loadAll = (limit?: number, start_time?: moment.Moment): Q.Promise => { var selector = { exchange: this._exchange, pair: this._pair }; - if (start_time) { + /*if (start_time) { selector["time"] = { $gte: start_time.toDate() }; - } + }*/ return this.loadInternal(selector, limit); }; From de8a96c1d9b9630804f1a63c6a07b3bb9cb106d3 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 14:05:36 +0200 Subject: [PATCH 107/202] Fixed calcs. --- src/admin/trades.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 36c7450ea..691960917 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -94,6 +94,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri } if (!exists) $scope.trade_statuses.push(new DisplayTrade($scope, t)); else if (unset>-1) $scope.trade_statuses.splice(unset, 1); + $scope.trade_statuses.sort(function(a,b){return a.quantity-a.allocb.quantity-b.alloc?-1:0);}); if ($scope.sound) { var audio = new Audio('http://antminer/a.mp3'); audio.volume = 0.5; From 8caf7fc7a0dc1009496b23697136b98fb542f231 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 14:18:31 +0200 Subject: [PATCH 108/202] Fixed calcs. --- src/admin/trades.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 691960917..50b151df9 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -82,19 +82,25 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri var addTrade = t => { var exists = 0; - var unset = -1; for(var i = 0;i<$scope.trade_statuses.length;i++) { if ($scope.trade_statuses[i].tradeId==t.tradeId) { exists = 1; $scope.trade_statuses[i].alloc = t.alloc; $scope.trade_statuses[i].allocprice = t.allocprice; - if ($scope.trade_statuses[i].alloc>=$scope.trade_statuses[i].quantity) - unset = i; } } if (!exists) $scope.trade_statuses.push(new DisplayTrade($scope, t)); - else if (unset>-1) $scope.trade_statuses.splice(unset, 1); - $scope.trade_statuses.sort(function(a,b){return a.quantity-a.allocb.quantity-b.alloc?-1:0);}); + var _whileDone = function(){ + for(var i = 0;i<$scope.trade_statuses.length;i++) + if ($scope.trade_statuses[i].alloc>=$scope.trade_statuses[i].quantity) + return i; + return -1; + }; + var _done = _whileDone(); + while(_done>-1) { + $scope.trade_statuses.splice(_done, 1); + _done = _whileDone(); + } if ($scope.sound) { var audio = new Audio('http://antminer/a.mp3'); audio.volume = 0.5; From 82922dea376aec8a9b1a7b28830e4d68c4a7a29b Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 14:24:52 +0200 Subject: [PATCH 109/202] Fixed calcs. --- src/service/quoting-engine.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/quoting-engine.ts b/src/service/quoting-engine.ts index 2d5f57165..c156c59e0 100644 --- a/src/service/quoting-engine.ts +++ b/src/service/quoting-engine.ts @@ -102,7 +102,7 @@ export class QuotingEngine { unrounded.askPx = null; unrounded.askSz = null; if (params.aggressivePositionRebalancing) - unrounded.bidSz = Math.min(params.aprMultiplier*params.size, targetBasePosition - totalBasePosition); + unrounded.bidSz = Math.min(params.aprMultiplier*params.size*2, targetBasePosition - totalBasePosition); } if (totalBasePosition > targetBasePosition + params.positionDivergence) { From 54e6c239b4631e9be461c93d55bddbb642f53bb4 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 14:28:21 +0200 Subject: [PATCH 110/202] Fixed calcs. --- src/service/quoting-engine.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/quoting-engine.ts b/src/service/quoting-engine.ts index c156c59e0..a3f9f5211 100644 --- a/src/service/quoting-engine.ts +++ b/src/service/quoting-engine.ts @@ -97,12 +97,12 @@ export class QuotingEngine { var latestPosition = this._positionBroker.latestReport; var totalBasePosition = latestPosition.baseAmount + latestPosition.baseHeldAmount; - + unrounded.bidSz *= 2; if (totalBasePosition < targetBasePosition - params.positionDivergence) { unrounded.askPx = null; unrounded.askSz = null; if (params.aggressivePositionRebalancing) - unrounded.bidSz = Math.min(params.aprMultiplier*params.size*2, targetBasePosition - totalBasePosition); + unrounded.bidSz = Math.min(params.aprMultiplier*params.size, targetBasePosition - totalBasePosition); } if (totalBasePosition > targetBasePosition + params.positionDivergence) { From 77595e24bffa1ea82f24bca8eb2eee600f1c358b Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 14:34:01 +0200 Subject: [PATCH 111/202] Fixed calcs. --- src/service/safety.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/service/safety.ts b/src/service/safety.ts index f6380bae5..9acf80315 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -107,21 +107,21 @@ export class SafetyCalculator { } trades.sort(function(a,b){return a.priceb.price?-1:0);}); for (var ti = 0;titrades[ti].price)) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].alloctrades[ti].price)) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].alloc=settings.size) break; + if (sellPq>=settings.size*2) break; } trades.sort(function(a,b){return a.price>b.price?1:(a.price=settings.size) break; + if (sellPq>=settings.size*2) break; } if (buyPq) buyPing /= buyPq; From 4e6d9d43cb22f440ba513176b741b2fbe213c10f Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 15:21:11 +0200 Subject: [PATCH 112/202] Fixed calcs. --- src/admin/trades.ts | 4 ++-- src/service/persister.ts | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 50b151df9..0a213c5e2 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -90,7 +90,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri } } if (!exists) $scope.trade_statuses.push(new DisplayTrade($scope, t)); - var _whileDone = function(){ + /*var _whileDone = function(){ for(var i = 0;i<$scope.trade_statuses.length;i++) if ($scope.trade_statuses[i].alloc>=$scope.trade_statuses[i].quantity) return i; @@ -100,7 +100,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri while(_done>-1) { $scope.trade_statuses.splice(_done, 1); _done = _whileDone(); - } + }*/ if ($scope.sound) { var audio = new Audio('http://antminer/a.mp3'); audio.volume = 0.5; diff --git a/src/service/persister.ts b/src/service/persister.ts index b8e94dc06..dd64ef8e7 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -207,7 +207,6 @@ export class Persister implements ILoadAll { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); - coll.deleteMany({ $where: "this.alloc >= this.quantity" }); }).done(); }; From 66465a486afa6f1f8e608b5cd5adca334a204d47 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 15:27:56 +0200 Subject: [PATCH 113/202] Fixed calcs. --- src/admin/trades.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 0a213c5e2..56e53ba65 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -90,6 +90,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri } } if (!exists) $scope.trade_statuses.push(new DisplayTrade($scope, t)); + $scope.trade_statuses.sort(function(a,b){return a.alloc>b.alloc?1:(a.alloc=$scope.trade_statuses[i].quantity) From 406174b7b751e015985961f25e33fc3ab4f940cf Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 15:39:48 +0200 Subject: [PATCH 114/202] Fixed calcs. --- src/admin/trades.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 56e53ba65..8526a89a3 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -58,9 +58,9 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri rowHeight: 20, headerRowHeight: 20, columnDefs: [ - {width: 75, field:'time', displayName:'t', cellFilter: 'momentShortDate', + {width: 75, field:'time', displayName:'t', cellFilter: 'momentShortDate'/*, sortingAlgorithm: (a: moment.Moment, b: moment.Moment) => a.diff(b), - sort: { direction: uiGridConstants.DESC, priority: 1} }, + sort: { direction: uiGridConstants.DESC, priority: 1} */}, {width: 50, field:'price', displayName:'px', cellFilter: 'currency'}, {width: 50, field:'quantity', displayName:'qty'}, {width: 20, field:'side', displayName:'side', cellClass: (grid, row, col, rowRenderIndex, colRenderIndex) => { @@ -76,7 +76,8 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri }}, {width: 60, field:'value', displayName:'val', cellFilter: 'currency:"$":3'}, {width: 50, field:'alloc', displayName:'alloc'}, - {width: 55, field:'allocprice', displayName:'px', cellFilter: 'currency'} + {width: 55, field:'allocprice', displayName:'px', cellFilter: 'currency', + sort: { direction: uiGridConstants.DESC, priority: 1}} ] }; @@ -90,7 +91,6 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri } } if (!exists) $scope.trade_statuses.push(new DisplayTrade($scope, t)); - $scope.trade_statuses.sort(function(a,b){return a.alloc>b.alloc?1:(a.alloc=$scope.trade_statuses[i].quantity) From c6f48f666ad58cc3e1002d245f8a0e9cad9d4209 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 15:50:17 +0200 Subject: [PATCH 115/202] Fixed calcs. --- src/admin/trades.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 8526a89a3..d69be202b 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -58,9 +58,9 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri rowHeight: 20, headerRowHeight: 20, columnDefs: [ - {width: 75, field:'time', displayName:'t', cellFilter: 'momentShortDate'/*, + {width: 75, field:'time', displayName:'t', cellFilter: 'momentShortDate', sortingAlgorithm: (a: moment.Moment, b: moment.Moment) => a.diff(b), - sort: { direction: uiGridConstants.DESC, priority: 1} */}, + sort: { direction: uiGridConstants.DESC, priority: 2} }, {width: 50, field:'price', displayName:'px', cellFilter: 'currency'}, {width: 50, field:'quantity', displayName:'qty'}, {width: 20, field:'side', displayName:'side', cellClass: (grid, row, col, rowRenderIndex, colRenderIndex) => { From f1d274fdcde149b7150fc420e3fd42535087c734 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 15:51:37 +0200 Subject: [PATCH 116/202] Fixed calcs. --- src/admin/trades.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index d69be202b..2a305041d 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -60,7 +60,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri columnDefs: [ {width: 75, field:'time', displayName:'t', cellFilter: 'momentShortDate', sortingAlgorithm: (a: moment.Moment, b: moment.Moment) => a.diff(b), - sort: { direction: uiGridConstants.DESC, priority: 2} }, + sort: { direction: uiGridConstants.DESC, priority: 1} }, {width: 50, field:'price', displayName:'px', cellFilter: 'currency'}, {width: 50, field:'quantity', displayName:'qty'}, {width: 20, field:'side', displayName:'side', cellClass: (grid, row, col, rowRenderIndex, colRenderIndex) => { @@ -77,7 +77,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri {width: 60, field:'value', displayName:'val', cellFilter: 'currency:"$":3'}, {width: 50, field:'alloc', displayName:'alloc'}, {width: 55, field:'allocprice', displayName:'px', cellFilter: 'currency', - sort: { direction: uiGridConstants.DESC, priority: 1}} + sort: { direction: uiGridConstants.DESC, priority: 2}} ] }; From 808b60886d3c81f78a1424ba2181d6f8d05879be Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 15:53:08 +0200 Subject: [PATCH 117/202] Fixed calcs. --- src/admin/trades.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 2a305041d..0ab6f11e6 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -60,7 +60,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri columnDefs: [ {width: 75, field:'time', displayName:'t', cellFilter: 'momentShortDate', sortingAlgorithm: (a: moment.Moment, b: moment.Moment) => a.diff(b), - sort: { direction: uiGridConstants.DESC, priority: 1} }, + sort: { direction: uiGridConstants.ASC, priority: 1} }, {width: 50, field:'price', displayName:'px', cellFilter: 'currency'}, {width: 50, field:'quantity', displayName:'qty'}, {width: 20, field:'side', displayName:'side', cellClass: (grid, row, col, rowRenderIndex, colRenderIndex) => { From 49e9d0d64f78a350c89710fc94d15554b52ed0e0 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 15:54:05 +0200 Subject: [PATCH 118/202] Fixed calcs. --- src/admin/trades.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 0ab6f11e6..6cce7f807 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -60,7 +60,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri columnDefs: [ {width: 75, field:'time', displayName:'t', cellFilter: 'momentShortDate', sortingAlgorithm: (a: moment.Moment, b: moment.Moment) => a.diff(b), - sort: { direction: uiGridConstants.ASC, priority: 1} }, + sort: { direction: uiGridConstants.ASC, priority: 2} }, {width: 50, field:'price', displayName:'px', cellFilter: 'currency'}, {width: 50, field:'quantity', displayName:'qty'}, {width: 20, field:'side', displayName:'side', cellClass: (grid, row, col, rowRenderIndex, colRenderIndex) => { @@ -77,7 +77,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri {width: 60, field:'value', displayName:'val', cellFilter: 'currency:"$":3'}, {width: 50, field:'alloc', displayName:'alloc'}, {width: 55, field:'allocprice', displayName:'px', cellFilter: 'currency', - sort: { direction: uiGridConstants.DESC, priority: 2}} + sort: { direction: uiGridConstants.DESC, priority: 1}} ] }; From baae0a5845bbda3c976068b56c92a483a9a77f0a Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 15:58:58 +0200 Subject: [PATCH 119/202] Fixed calcs. --- src/admin/trades.ts | 6 +++--- src/service/backtest.ts | 2 +- src/service/broker.ts | 3 ++- src/service/persister.ts | 6 +++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 6cce7f807..68b308b7b 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -60,7 +60,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri columnDefs: [ {width: 75, field:'time', displayName:'t', cellFilter: 'momentShortDate', sortingAlgorithm: (a: moment.Moment, b: moment.Moment) => a.diff(b), - sort: { direction: uiGridConstants.ASC, priority: 2} }, + sort: { direction: uiGridConstants.ASC, priority: 1} }, {width: 50, field:'price', displayName:'px', cellFilter: 'currency'}, {width: 50, field:'quantity', displayName:'qty'}, {width: 20, field:'side', displayName:'side', cellClass: (grid, row, col, rowRenderIndex, colRenderIndex) => { @@ -76,8 +76,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri }}, {width: 60, field:'value', displayName:'val', cellFilter: 'currency:"$":3'}, {width: 50, field:'alloc', displayName:'alloc'}, - {width: 55, field:'allocprice', displayName:'px', cellFilter: 'currency', - sort: { direction: uiGridConstants.DESC, priority: 1}} + {width: 55, field:'allocprice', displayName:'px', cellFilter: 'currency'} ] }; @@ -86,6 +85,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri for(var i = 0;i<$scope.trade_statuses.length;i++) { if ($scope.trade_statuses[i].tradeId==t.tradeId) { exists = 1; + $scope.trade_statuses[i].time = t.time; $scope.trade_statuses[i].alloc = t.alloc; $scope.trade_statuses[i].allocprice = t.allocprice; } diff --git a/src/service/backtest.ts b/src/service/backtest.ts index f78411eb9..ee89dc11d 100644 --- a/src/service/backtest.ts +++ b/src/service/backtest.ts @@ -312,7 +312,7 @@ export class BacktestPersister implements Persister.ILoadAll, Persister.IL public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { }; - public repersist = (report: T, tradeId: string, alloc?: number, _allocprice?: number) => { }; + public repersist = (report: T, tradeId: string, alloc?: number, _allocprice?: number, _time?: moment.Moment) => { }; public loadLatest = (): Q.Promise => { if (this.initialData) diff --git a/src/service/broker.ts b/src/service/broker.ts index 2e1297c26..e24aacca8 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -180,8 +180,9 @@ export class OrderBroker implements Interfaces.IOrderBroker { this._trades[i].allocprice = ((allocQty*trade.price) + (this._trades[i].alloc*this._trades[i].allocprice)) / (this._trades[i].alloc+allocQty); this._trades[i].alloc += allocQty; trade.quantity -= allocQty; + this._trades[i].time = trade.time; this._tradePublisher.publish(this._trades[i]); - this._tradePersister.repersist(this._trades[i], this._trades[i].tradeId, this._trades[i].alloc, this._trades[i].allocprice); + this._tradePersister.repersist(this._trades[i], this._trades[i].tradeId, this._trades[i].alloc, this._trades[i].allocprice, this._trades[i].time); if (trade.quantity>0) this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { this._reTrade(reTrade, trade); }); break; } diff --git a/src/service/persister.ts b/src/service/persister.ts index dd64ef8e7..c3539ce69 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -54,7 +54,7 @@ export class LoaderSaver { export interface IPersist { persist(data: T): void; perfind(report: T, side: Models.Side, width?: number, price?: number): any; - repersist(report: T, tradeId: string, alloc?: number, _allocprice?: number): void; + repersist(report: T, tradeId: string, alloc?: number, _allocprice?: number, _time?: moment.Moment): void; } export interface ILoadLatest extends IPersist { @@ -94,7 +94,7 @@ export class RepositoryPersister implements ILoadLatest { }; + public perfind = (report: T, side: Models.Side, width?: number, price?: number, _time?: moment.Moment): any => { }; public repersist = (report: T, tradeId: string, alloc?: number, _allocprice?: number) => { }; @@ -200,7 +200,7 @@ export class Persister implements ILoadAll { return deferred.promise; }; - public repersist = (report: T, _tradeId: string, _alloc?: number, _allocprice?: number) => { + public repersist = (report: T, _tradeId: string, _alloc?: number, _allocprice?: number, _time?: moment.Moment) => { this.collection.then(coll => { this._saver(report); coll.updateOne({ tradeId: _tradeId }, { $set: { alloc : _alloc, allocprice : _allocprice } }, err => { From 0d7440afd66a29ca0a3f5c46dfb403fdbd7e3021 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 15:59:40 +0200 Subject: [PATCH 120/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index c3539ce69..a0b23a6e6 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -203,7 +203,7 @@ export class Persister implements ILoadAll { public repersist = (report: T, _tradeId: string, _alloc?: number, _allocprice?: number, _time?: moment.Moment) => { this.collection.then(coll => { this._saver(report); - coll.updateOne({ tradeId: _tradeId }, { $set: { alloc : _alloc, allocprice : _allocprice } }, err => { + coll.updateOne({ tradeId: _tradeId }, { $set: { time: _time, alloc : _alloc, allocprice : _allocprice } }, err => { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); From a06d70a711d2edf148066fcf8b37ef7b7203d6e5 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sun, 24 Jul 2016 16:04:22 +0200 Subject: [PATCH 121/202] Fixed calcs. --- src/admin/trades.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 68b308b7b..ab9604dc8 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -60,7 +60,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri columnDefs: [ {width: 75, field:'time', displayName:'t', cellFilter: 'momentShortDate', sortingAlgorithm: (a: moment.Moment, b: moment.Moment) => a.diff(b), - sort: { direction: uiGridConstants.ASC, priority: 1} }, + sort: { direction: uiGridConstants.DESC, priority: 1} }, {width: 50, field:'price', displayName:'px', cellFilter: 'currency'}, {width: 50, field:'quantity', displayName:'qty'}, {width: 20, field:'side', displayName:'side', cellClass: (grid, row, col, rowRenderIndex, colRenderIndex) => { From 010946cf42538ec6944b6972cb845aec87ca4a66 Mon Sep 17 00:00:00 2001 From: ctubio Date: Mon, 25 Jul 2016 19:38:52 +0200 Subject: [PATCH 122/202] Fixed calcs. --- src/admin/trades.ts | 4 ++-- src/service/persister.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index ab9604dc8..1ececb3f4 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -81,10 +81,10 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri }; var addTrade = t => { - var exists = 0; + var exists = false; for(var i = 0;i<$scope.trade_statuses.length;i++) { if ($scope.trade_statuses[i].tradeId==t.tradeId) { - exists = 1; + exists = true; $scope.trade_statuses[i].time = t.time; $scope.trade_statuses[i].alloc = t.alloc; $scope.trade_statuses[i].allocprice = t.allocprice; diff --git a/src/service/persister.ts b/src/service/persister.ts index a0b23a6e6..76dfbabd9 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -203,7 +203,7 @@ export class Persister implements ILoadAll { public repersist = (report: T, _tradeId: string, _alloc?: number, _allocprice?: number, _time?: moment.Moment) => { this.collection.then(coll => { this._saver(report); - coll.updateOne({ tradeId: _tradeId }, { $set: { time: _time, alloc : _alloc, allocprice : _allocprice } }, err => { + coll.updateOne({ tradeId: _tradeId }, { $set: { time: _time.format('YY-M-d h:mm:ss'), alloc : _alloc, allocprice : _allocprice } }, err => { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); From d0353dd79dbf305b7f1e4af7140a2d9150718b6c Mon Sep 17 00:00:00 2001 From: ctubio Date: Mon, 25 Jul 2016 20:09:50 +0200 Subject: [PATCH 123/202] Fixed calcs. --- src/service/main.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/service/main.ts b/src/service/main.ts index 167ceae54..482ba6d68 100644 --- a/src/service/main.ts +++ b/src/service/main.ts @@ -114,8 +114,7 @@ function ParseCurrencyPair(raw: string) : Models.CurrencyPair { var pair = ParseCurrencyPair(config.GetString("TradedPair")); var defaultActive : Models.SerializedQuotesActive = new Models.SerializedQuotesActive(false, moment.unix(1)); -var defaultQuotingParameters : Models.QuotingParameters = new Models.QuotingParameters(1, 1, Models.QuotingMode.Top, - Models.FairValueModel.BBO, 2, 2, true, Models.AutoPositionMode.EwmaBasic, false, 2.5, 84, .095, 2*.095, .095, 3, .1); +var defaultQuotingParameters : Models.QuotingParameters = new Models.QuotingParameters(2, 0.01, Models.QuotingMode.Boomerang, Models.FairValueModel.BBO, 1, 0.9, true, Models.AutoPositionMode.EwmaBasic, false, 0.9, 569, .095, 2*.095, .095, 3, .1); var backTestSimulationSetup = (inputData : Array, parameters : Backtest.BacktestParameters) => { var timeProvider : Utils.ITimeProvider = new Backtest.BacktestTimeProvider(_.first(inputData).time, _.last(inputData).time); From f68cd36b2d5084dc6c4076223c4f79d9fa132007 Mon Sep 17 00:00:00 2001 From: ctubio Date: Mon, 25 Jul 2016 20:45:15 +0200 Subject: [PATCH 124/202] Added sounds. --- src/admin/trades.ts | 19 +++++++++++++------ src/static/a.mp3 | Bin 0 -> 46957 bytes src/static/z.wav | Bin 0 -> 7354 bytes 3 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 src/static/a.mp3 create mode 100644 src/static/z.wav diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 1ececb3f4..b44b7b01f 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -88,9 +88,21 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri $scope.trade_statuses[i].time = t.time; $scope.trade_statuses[i].alloc = t.alloc; $scope.trade_statuses[i].allocprice = t.allocprice; + if ($scope.sound) { + var audio = new Audio('/z.mp3'); + audio.volume = 0.5; + audio.play(); + } + } + } + if (!exists) { + $scope.trade_statuses.push(new DisplayTrade($scope, t)); + if ($scope.sound) { + var audio = new Audio('/a.wav'); + audio.volume = 0.5; + audio.play(); } } - if (!exists) $scope.trade_statuses.push(new DisplayTrade($scope, t)); /*var _whileDone = function(){ for(var i = 0;i<$scope.trade_statuses.length;i++) if ($scope.trade_statuses[i].alloc>=$scope.trade_statuses[i].quantity) @@ -102,11 +114,6 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri $scope.trade_statuses.splice(_done, 1); _done = _whileDone(); }*/ - if ($scope.sound) { - var audio = new Audio('http://antminer/a.mp3'); - audio.volume = 0.5; - audio.play(); - } }; var sub = subscriberFactory.getSubscriber($scope, Messaging.Topics.Trades) diff --git a/src/static/a.mp3 b/src/static/a.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..694dd5aafe2be45d44f302720ac3a14459184d92 GIT binary patch literal 46957 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 I|KIz60lQrd+5i9m literal 0 HcmV?d00001 diff --git a/src/static/z.wav b/src/static/z.wav new file mode 100644 index 0000000000000000000000000000000000000000..6fdd51c7faabb4d8b9ea8ccd647e85dc3a63f577 GIT binary patch literal 7354 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 kYhT-coirewlXbEcK=AaFA=x>4+H7$IsgCw literal 0 HcmV?d00001 From b7d6f112918a7204d7d5e3564a2fe2467712e3f5 Mon Sep 17 00:00:00 2001 From: ctubio Date: Mon, 25 Jul 2016 23:09:26 +0200 Subject: [PATCH 125/202] Fixed calcs. --- src/admin/trades.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index b44b7b01f..0e0aff97b 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -89,7 +89,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri $scope.trade_statuses[i].alloc = t.alloc; $scope.trade_statuses[i].allocprice = t.allocprice; if ($scope.sound) { - var audio = new Audio('/z.mp3'); + var audio = new Audio('/z.wav'); audio.volume = 0.5; audio.play(); } @@ -98,7 +98,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri if (!exists) { $scope.trade_statuses.push(new DisplayTrade($scope, t)); if ($scope.sound) { - var audio = new Audio('/a.wav'); + var audio = new Audio('/a.mp3'); audio.volume = 0.5; audio.play(); } From 65fca11664bc44c2e5b54d98990fdcb492f0514a Mon Sep 17 00:00:00 2001 From: ctubio Date: Mon, 25 Jul 2016 23:30:47 +0200 Subject: [PATCH 126/202] Fixed calcs. --- src/service/backtest.ts | 2 +- src/service/broker.ts | 10 +++++----- src/service/persister.ts | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/service/backtest.ts b/src/service/backtest.ts index ee89dc11d..c393a5f53 100644 --- a/src/service/backtest.ts +++ b/src/service/backtest.ts @@ -310,7 +310,7 @@ export class BacktestPersister implements Persister.ILoadAll, Persister.IL public persist = (report: T) => { }; - public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { }; + public perfind = (report: T, side: Models.Side, width?: number, price?: number): Q.Promise => { }; public repersist = (report: T, tradeId: string, alloc?: number, _allocprice?: number, _time?: moment.Moment) => { }; diff --git a/src/service/broker.ts b/src/service/broker.ts index e24aacca8..2ae3a7f76 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -169,21 +169,21 @@ export class OrderBroker implements Interfaces.IOrderBroker { this.onOrderUpdate(rpt); }; - private _reTrade = (reTrade: Models.Trade, trade: Models.Trade) => { + private _reTrade = (reTrades: Models.Trade[], trade: Models.Trade) => { var gowhile = true; - while (gowhile && trade.quantity>0 && reTrade!=null && reTrade) { + while (gowhile && trade.quantity>0 && reTrades!=null && reTrades.length) { + var reTrade = reTrades.shift(); gowhile = false; for(var i = 0;i0) this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { this._reTrade(reTrade, trade); }); break; } } @@ -295,7 +295,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { const trade = new Models.Trade(o.orderId+"."+o.version, o.time, o.exchange, o.pair, o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, 0, feeCharged); this.Trade.trigger(trade); - this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrade => { this._reTrade(reTrade, trade); }); + this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrades => { this._reTrade(reTrades, trade); }); } }; diff --git a/src/service/persister.ts b/src/service/persister.ts index 76dfbabd9..251842a02 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -53,7 +53,7 @@ export class LoaderSaver { export interface IPersist { persist(data: T): void; - perfind(report: T, side: Models.Side, width?: number, price?: number): any; + perfind(report: T, side: Models.Side, width?: number, price?: number): Q.Promise; repersist(report: T, tradeId: string, alloc?: number, _allocprice?: number, _time?: moment.Moment): void; } @@ -94,7 +94,7 @@ export class RepositoryPersister implements ILoadLatest { }; + public perfind = (report: T, side: Models.Side, width?: number, price?: number, _time?: moment.Moment): Q.Promise => { }; public repersist = (report: T, tradeId: string, alloc?: number, _allocprice?: number) => { }; @@ -175,14 +175,14 @@ export class Persister implements ILoadAll { }).done(); }; - public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { - var deferred = Q.defer(); + public perfind = (report: T, side: Models.Side, width?: number, price?: number): Q.Promise => { + var deferred = Q.defer(); this.collection.then(coll => { coll.find({ $and: [ { price: side==Models.Side.Bid?{ $gt: width+price }:{ $lt: price-width } }, { side: side==Models.Side.Bid?1:0 }, { $where: "this.quantity - this.alloc > 0" } - ] }).limit(1).sort({ alloc: 1, price: side==Models.Side.Bid?1:-1 }) + ] }).limit(10000).sort({ alloc: 1, price: side==Models.Side.Bid?1:-1 }) .toArray((err, arr) => { if (err) { deferred.reject(err); @@ -191,8 +191,8 @@ export class Persister implements ILoadAll { deferred.resolve(null); } else { - this._loader(arr[0]); - deferred.resolve(arr[0]); + this._loader(arr); + deferred.resolve(arr); } });; }).done(); From cfb9a0e45b40621b2f32caf543b132caa1d73573 Mon Sep 17 00:00:00 2001 From: ctubio Date: Mon, 25 Jul 2016 23:34:05 +0200 Subject: [PATCH 127/202] Fixed calcs. --- src/service/backtest.ts | 2 +- src/service/persister.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/service/backtest.ts b/src/service/backtest.ts index c393a5f53..ee89dc11d 100644 --- a/src/service/backtest.ts +++ b/src/service/backtest.ts @@ -310,7 +310,7 @@ export class BacktestPersister implements Persister.ILoadAll, Persister.IL public persist = (report: T) => { }; - public perfind = (report: T, side: Models.Side, width?: number, price?: number): Q.Promise => { }; + public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { }; public repersist = (report: T, tradeId: string, alloc?: number, _allocprice?: number, _time?: moment.Moment) => { }; diff --git a/src/service/persister.ts b/src/service/persister.ts index 251842a02..0d61ccacc 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -53,7 +53,7 @@ export class LoaderSaver { export interface IPersist { persist(data: T): void; - perfind(report: T, side: Models.Side, width?: number, price?: number): Q.Promise; + perfind(report: T, side: Models.Side, width?: number, price?: number): any; repersist(report: T, tradeId: string, alloc?: number, _allocprice?: number, _time?: moment.Moment): void; } @@ -94,7 +94,7 @@ export class RepositoryPersister implements ILoadLatest => { }; + public perfind = (report: T, side: Models.Side, width?: number, price?: number, _time?: moment.Moment): any => { }; public repersist = (report: T, tradeId: string, alloc?: number, _allocprice?: number) => { }; @@ -175,7 +175,7 @@ export class Persister implements ILoadAll { }).done(); }; - public perfind = (report: T, side: Models.Side, width?: number, price?: number): Q.Promise => { + public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { var deferred = Q.defer(); this.collection.then(coll => { coll.find({ $and: [ From 3a5a94749bfc15e3c7741b62dd942fd8ae1f48b2 Mon Sep 17 00:00:00 2001 From: ctubio Date: Mon, 25 Jul 2016 23:45:34 +0200 Subject: [PATCH 128/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 0d61ccacc..f47be836a 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -191,7 +191,7 @@ export class Persister implements ILoadAll { deferred.resolve(null); } else { - this._loader(arr); + _.forEach(arr, this._loader); deferred.resolve(arr); } });; From 5838798af3fcbdf961bb885fc5bfbc9fda5c319d Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 26 Jul 2016 19:25:36 +0200 Subject: [PATCH 129/202] Fixed calcs. --- src/admin/trades.ts | 4 ++-- src/service/broker.ts | 2 +- src/static/index.html | 7 +++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 0e0aff97b..1be2740c7 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -89,7 +89,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri $scope.trade_statuses[i].alloc = t.alloc; $scope.trade_statuses[i].allocprice = t.allocprice; if ($scope.sound) { - var audio = new Audio('/z.wav'); + var audio = new Audio('/a.wav'); audio.volume = 0.5; audio.play(); } @@ -98,7 +98,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri if (!exists) { $scope.trade_statuses.push(new DisplayTrade($scope, t)); if ($scope.sound) { - var audio = new Audio('/a.mp3'); + var audio = new Audio('/z.mp3'); audio.volume = 0.5; audio.play(); } diff --git a/src/service/broker.ts b/src/service/broker.ts index 2ae3a7f76..762bc69e4 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -193,6 +193,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { this._tradePersister.persist(trade); this._trades.push(trade); } + this.Trade.trigger(trade); }; public onOrderUpdate = (osr : Models.OrderStatusReport) => { @@ -294,7 +295,6 @@ export class OrderBroker implements Interfaces.IOrderBroker { const trade = new Models.Trade(o.orderId+"."+o.version, o.time, o.exchange, o.pair, o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, 0, feeCharged); - this.Trade.trigger(trade); this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrades => { this._reTrade(reTrades, trade); }); } }; diff --git a/src/static/index.html b/src/static/index.html index ac62533a5..7248e193c 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -138,6 +138,13 @@

data-placement="bottom">Cancel All Open Orders +
  • + +
  • From 5d0f3de0ced365b81bba954651282bfa3807fd49 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 26 Jul 2016 19:40:38 +0200 Subject: [PATCH 130/202] Fixed calcs. --- src/admin/client.ts | 10 ++++++--- src/common/messaging.ts | 21 +++++++++--------- src/common/models.ts | 4 ++++ src/service/broker.ts | 47 +++++++++++++++++++++++++++++++++++++++++ src/service/main.ts | 3 ++- src/static/index.html | 2 +- 6 files changed, 72 insertions(+), 15 deletions(-) diff --git a/src/admin/client.ts b/src/admin/client.ts index af48bf356..f4e500933 100644 --- a/src/admin/client.ts +++ b/src/admin/client.ts @@ -39,6 +39,7 @@ interface MainWindowScope extends ng.IScope { exch_name : string; pair_name : string; cancelAllOrders(); + cleanAllOrders(); } class DisplayOrder { @@ -84,10 +85,13 @@ var uiCtrl = ($scope : MainWindowScope, $log : ng.ILogService, subscriberFactory : Shared.SubscriberFactory, fireFactory : Shared.FireFactory) => { - + var cancelAllFirer = fireFactory.getFire(Messaging.Topics.CancelAllOrders); $scope.cancelAllOrders = () => cancelAllFirer.fire(new Models.CancelAllOrdersRequest()); - + + var cleanAllFirer = fireFactory.getFire(Messaging.Topics.CleanAllOrders); + $scope.cleanAllOrders = () => cleanAllFirer.fire(new Models.CleanAllOrdersRequest()); + $scope.order = new DisplayOrder(fireFactory, $log); $scope.pair = null; @@ -130,7 +134,7 @@ var requires = ['ui.bootstrap', Trades.tradeListDirective, MarketQuoting.marketQuotingDirective, MarketTrades.marketTradeDirective, - Messages.messagesDirective, + Messages.messagesDirective, Position.positionDirective, Tbp.targetBasePositionDirective, TradeSafety.tradeSafetyDirective, diff --git a/src/common/messaging.ts b/src/common/messaging.ts index 18ba95e00..082ed1378 100644 --- a/src/common/messaging.ts +++ b/src/common/messaging.ts @@ -16,7 +16,7 @@ export interface IPublish { export class Publisher implements IPublish { private _snapshot : () => T[] = null; - constructor(private topic : string, + constructor(private topic : string, private _io : SocketIO.Server, snapshot : () => T[], private _log : (...args: any[]) => void) { @@ -28,7 +28,7 @@ export class Publisher implements IPublish { s.on("disconnect", () => { this._log("socket", s.id, "disconnected for Publisher", topic); }); - + s.on(Prefixes.SUBSCRIBE + "-" + topic, () => { if (this._snapshot !== null) { var snapshot = this._snapshot(); @@ -39,7 +39,7 @@ export class Publisher implements IPublish { }; this._io.on("connection", onConnection); - + Object.keys(this._io.sockets.connected).forEach(s => { onConnection(this._io.sockets.connected[s]); }); @@ -79,22 +79,22 @@ export class Subscriber implements ISubscribe { private _connectHandler : () => void = null; private _socket : SocketIOClient.Socket; - constructor(private topic : string, + constructor(private topic : string, io : SocketIOClient.Socket, private _log : (...args: any[]) => void) { this._socket = io; - + this._log("creating subscriber to", this.topic, "; connected?", this.connected); - - if (this.connected) + + if (this.connected) this.onConnect(); - + this._socket.on("connect", this.onConnect) .on("disconnect", this.onDisconnect) .on(Prefixes.MESSAGE + "-" + topic, this.onIncremental) .on(Prefixes.SNAPSHOT + "-" + topic, this.onSnapshot); } - + public get connected() : boolean { return this._socket.connected; } @@ -214,7 +214,7 @@ export class Receiver implements IReceive { _log("error in Receiver", e.stack, e.message); }); }; - + io.on("connection", onConnection); Object.keys(io.sockets.connected).forEach(s => { onConnection(io.sockets.connected[s]); @@ -254,4 +254,5 @@ export class Topics { static TargetBasePosition = "tbp"; static TradeSafetyValue = "tsv"; static CancelAllOrders = "cao"; + static CleanAllOrders = "kao"; } diff --git a/src/common/models.ts b/src/common/models.ts index 9d6c69d3b..33e468f43 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -397,3 +397,7 @@ export class TargetBasePositionValue { export class CancelAllOrdersRequest { constructor() {} } + +export class CleanAllOrdersRequest { + constructor() {} +} diff --git a/src/service/broker.ts b/src/service/broker.ts index 762bc69e4..ac1c485f7 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -92,6 +92,45 @@ export class OrderBroker implements Interfaces.IOrderBroker { return deferred.promise; } + cleanOpenOrders() : Q.Promise { + if (this._oeGateway.supportsCancelAllOpenOrders()) { + return this._oeGateway.cancelAllOpenOrders(); + } + + var deferred = Q.defer(); + + var lateCancels : {[id: string] : boolean} = {}; + for (var k in this._orderCache.allOrders) { + if (!(k in this._orderCache.allOrders)) continue; + var e : Models.OrderStatusReport = _.last(this._orderCache.allOrders[k]); + + if (e.pendingCancel) continue; + + switch (e.orderStatus) { + case Models.OrderStatus.New: + case Models.OrderStatus.Working: + this.cancelOrder(new Models.OrderCancel(e.orderId, e.exchange, this._timeProvider.utcNow())); + lateCancels[e.orderId] = false; + break; + } + } + + if (_.isEmpty(_.keys(lateCancels))) { + deferred.resolve(0); + } + + this.OrderUpdate.on(o => { + if (o.orderStatus === Models.OrderStatus.New || o.orderStatus === Models.OrderStatus.Working) + return; + + lateCancels[e.orderId] = true; + if (_.every(_.values(lateCancels))) + deferred.resolve(_.size(lateCancels)); + }); + + return deferred.promise; + } + OrderUpdate = new Utils.Evt(); private _cancelsWaitingForExchangeOrderId : {[clId : string] : Models.OrderCancel} = {}; @@ -321,6 +360,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { private _submittedOrderReciever : Messaging.IReceive, private _cancelOrderReciever : Messaging.IReceive, private _cancelAllOrdersReciever : Messaging.IReceive, + private _cleanAllOrdersReciever : Messaging.IReceive, private _messages : Messages.MessagesPubisher, private _orderCache : OrderStateCache, initOrders : Models.OrderStatusReport[], @@ -356,6 +396,13 @@ export class OrderBroker implements Interfaces.IOrderBroker { e => this._log.error(e, "error when cancelling all orders!")); }); + _cleanAllOrdersReciever.registerReceiver(o => { + this._log.info("handling cancel all orders request"); + this.cleanOpenOrders() + .then(x => this._log.info("cancelled all ", x, " open orders"), + e => this._log.error(e, "error when cancelling all orders!")); + }); + this._oeGateway.OrderUpdate.on(this.onOrderUpdate); _.each(initOrders, this.addOrderStatusToMemory); diff --git a/src/service/main.ts b/src/service/main.ts index 482ba6d68..eac8f6737 100644 --- a/src/service/main.ts +++ b/src/service/main.ts @@ -313,6 +313,7 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { var submitOrderReceiver = getReceiver(Messaging.Topics.SubmitNewOrder); var cancelOrderReceiver = getReceiver(Messaging.Topics.CancelOrder); var cancelAllOrdersReceiver = getReceiver(Messaging.Topics.CancelAllOrders); + var cleanAllOrdersReceiver = getReceiver(Messaging.Topics.CleanAllOrders); var gateway = classes.getExch(orderCache); @@ -324,7 +325,7 @@ var runTradingSystem = (classes: SimulationClasses) : Q.Promise => { var broker = new Broker.ExchangeBroker(pair, gateway.md, gateway.base, gateway.oe, connectivity); var orderBroker = new Broker.OrderBroker(timeProvider, paramsRepo, broker, gateway.oe, orderPersister, tradesPersister, orderStatusPublisher, - tradePublisher, submitOrderReceiver, cancelOrderReceiver, cancelAllOrdersReceiver, messages, orderCache, initOrders, initTrades); + tradePublisher, submitOrderReceiver, cancelOrderReceiver, cancelAllOrdersReceiver, cleanAllOrdersReceiver, messages, orderCache, initOrders, initTrades); var marketDataBroker = new Broker.MarketDataBroker(gateway.md, marketDataPublisher, marketDataPersister, messages); var positionBroker = new Broker.PositionBroker(timeProvider, broker, gateway.pg, positionPublisher, positionPersister, marketDataBroker); diff --git a/src/static/index.html b/src/static/index.html index 7248e193c..4654e3804 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -140,7 +140,7 @@

  • From 57628857257aad5b820e3db02076895d5622feb2 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 26 Jul 2016 20:37:40 +0200 Subject: [PATCH 131/202] Fixed calcs. --- src/admin/trades.ts | 42 +++++++++++++++++++++++++--------------- src/service/broker.ts | 32 +++++++++++++++++++++++++----- src/service/persister.ts | 14 ++++++++++---- 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 1be2740c7..e6c583a0f 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -81,28 +81,38 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri }; var addTrade = t => { - var exists = false; - for(var i = 0;i<$scope.trade_statuses.length;i++) { - if ($scope.trade_statuses[i].tradeId==t.tradeId) { - exists = true; - $scope.trade_statuses[i].time = t.time; - $scope.trade_statuses[i].alloc = t.alloc; - $scope.trade_statuses[i].allocprice = t.allocprice; + if (t.alloc<0) { + for(var i = 0;i<$scope.trade_statuses.length;i++) { + if ($scope.trade_statuses[i].tradeId==t.tradeId) { + $scope.trade_statuses.splice(i, 1); + break; + } + } + } else { + var exists = false; + for(var i = 0;i<$scope.trade_statuses.length;i++) { + if ($scope.trade_statuses[i].tradeId==t.tradeId) { + exists = true; + $scope.trade_statuses[i].time = t.time; + $scope.trade_statuses[i].alloc = t.alloc; + $scope.trade_statuses[i].allocprice = t.allocprice; + if ($scope.sound) { + var audio = new Audio('/a.wav'); + audio.volume = 0.5; + audio.play(); + } + break; + } + } + if (!exists) { + $scope.trade_statuses.push(new DisplayTrade($scope, t)); if ($scope.sound) { - var audio = new Audio('/a.wav'); + var audio = new Audio('/z.mp3'); audio.volume = 0.5; audio.play(); } } } - if (!exists) { - $scope.trade_statuses.push(new DisplayTrade($scope, t)); - if ($scope.sound) { - var audio = new Audio('/z.mp3'); - audio.volume = 0.5; - audio.play(); - } - } /*var _whileDone = function(){ for(var i = 0;i<$scope.trade_statuses.length;i++) if ($scope.trade_statuses[i].alloc>=$scope.trade_statuses[i].quantity) diff --git a/src/service/broker.ts b/src/service/broker.ts index ac1c485f7..b244595f2 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -93,11 +93,33 @@ export class OrderBroker implements Interfaces.IOrderBroker { } cleanOpenOrders() : Q.Promise { - if (this._oeGateway.supportsCancelAllOpenOrders()) { - return this._oeGateway.cancelAllOpenOrders(); + var deferred = Q.defer(); + + var lateCleans : {[id: string] : boolean} = {}; + for(var i = 0;i(); + if (_.isEmpty(_.keys(lateCleans))) { + deferred.resolve(0); + } + + for (var k in lateCleans) { + if (!(k in lateCleans)) continue; + for(var i = 0;i { this._log.info("handling cancel all orders request"); this.cleanOpenOrders() - .then(x => this._log.info("cancelled all ", x, " open orders"), - e => this._log.error(e, "error when cancelling all orders!")); + .then(x => this._log.info("cleaned all ", x, " closed orders"), + e => this._log.error(e, "error when cleaning all orders!")); }); this._oeGateway.OrderUpdate.on(this.onOrderUpdate); diff --git a/src/service/persister.ts b/src/service/persister.ts index f47be836a..1b8884595 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -203,10 +203,16 @@ export class Persister implements ILoadAll { public repersist = (report: T, _tradeId: string, _alloc?: number, _allocprice?: number, _time?: moment.Moment) => { this.collection.then(coll => { this._saver(report); - coll.updateOne({ tradeId: _tradeId }, { $set: { time: _time.format('YY-M-d h:mm:ss'), alloc : _alloc, allocprice : _allocprice } }, err => { - if (err) - this._log.error(err, "Unable to repersist", this._dbName, report); - }); + if (_alloc<0) + coll['delete']({ tradeId: _tradeId }, err => { + if (err) + this._log.error(err, "Unable to repersist", this._dbName, report); + }); + else + coll.updateOne({ tradeId: _tradeId }, { $set: { time: _time.format('Y-MM-DD HH:mm:ss'), alloc : _alloc, allocprice : _allocprice } }, err => { + if (err) + this._log.error(err, "Unable to repersist", this._dbName, report); + }); }).done(); }; From 7aa6c6f7100910c38b22d00de8af9feea5e5918f Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 26 Jul 2016 20:41:02 +0200 Subject: [PATCH 132/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 1b8884595..c93cd6c11 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -204,7 +204,7 @@ export class Persister implements ILoadAll { this.collection.then(coll => { this._saver(report); if (_alloc<0) - coll['delete']({ tradeId: _tradeId }, err => { + coll.deleteOne({ tradeId: _tradeId }, err => { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); From e35b9c8bda72e9460c23015df4fc4d8a93146621 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 26 Jul 2016 21:08:55 +0200 Subject: [PATCH 133/202] Fixed calcs. --- src/admin/trades.ts | 13 ++------ src/service/backtest.ts | 2 +- src/service/broker.ts | 69 ++++++++++++++++------------------------ src/service/persister.ts | 10 +++--- 4 files changed, 35 insertions(+), 59 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index e6c583a0f..ca1b46e5d 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -94,6 +94,8 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri if ($scope.trade_statuses[i].tradeId==t.tradeId) { exists = true; $scope.trade_statuses[i].time = t.time; + $scope.trade_statuses[i].quantity = t.quantity; + $scope.trade_statuses[i].value = t.value; $scope.trade_statuses[i].alloc = t.alloc; $scope.trade_statuses[i].allocprice = t.allocprice; if ($scope.sound) { @@ -113,17 +115,6 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri } } } - /*var _whileDone = function(){ - for(var i = 0;i<$scope.trade_statuses.length;i++) - if ($scope.trade_statuses[i].alloc>=$scope.trade_statuses[i].quantity) - return i; - return -1; - }; - var _done = _whileDone(); - while(_done>-1) { - $scope.trade_statuses.splice(_done, 1); - _done = _whileDone(); - }*/ }; var sub = subscriberFactory.getSubscriber($scope, Messaging.Topics.Trades) diff --git a/src/service/backtest.ts b/src/service/backtest.ts index ee89dc11d..9f3730d22 100644 --- a/src/service/backtest.ts +++ b/src/service/backtest.ts @@ -312,7 +312,7 @@ export class BacktestPersister implements Persister.ILoadAll, Persister.IL public perfind = (report: T, side: Models.Side, width?: number, price?: number): any => { }; - public repersist = (report: T, tradeId: string, alloc?: number, _allocprice?: number, _time?: moment.Moment) => { }; + public repersist = (report: T, trade: Models.Trade) => { }; public loadLatest = (): Q.Promise => { if (this.initialData) diff --git a/src/service/broker.ts b/src/service/broker.ts index b244595f2..992ed1ba7 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -107,49 +107,21 @@ export class OrderBroker implements Interfaces.IOrderBroker { } for (var k in lateCleans) { - if (!(k in lateCleans)) continue; - for(var i = 0;i { - if (o.orderStatus === Models.OrderStatus.New || o.orderStatus === Models.OrderStatus.Working) - return; - - lateCancels[e.orderId] = true; - if (_.every(_.values(lateCancels))) - deferred.resolve(_.size(lateCancels)); - }); - return deferred.promise; } @@ -244,17 +216,30 @@ export class OrderBroker implements Interfaces.IOrderBroker { this._trades[i].alloc += allocQty; trade.quantity -= allocQty; this._tradePublisher.publish(this._trades[i]); - this._tradePersister.repersist(this._trades[i], this._trades[i].tradeId, this._trades[i].alloc, this._trades[i].allocprice, this._trades[i].time); + this._tradePersister.repersist(this._trades[i], this._trades[i]); break; } } } + this.Trade.trigger(trade); if (trade.quantity>0) { - this._tradePublisher.publish(trade); - this._tradePersister.persist(trade); - this._trades.push(trade); + var exists = false; + for(var i = 0;i { diff --git a/src/service/persister.ts b/src/service/persister.ts index c93cd6c11..126b76f51 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -54,7 +54,7 @@ export class LoaderSaver { export interface IPersist { persist(data: T): void; perfind(report: T, side: Models.Side, width?: number, price?: number): any; - repersist(report: T, tradeId: string, alloc?: number, _allocprice?: number, _time?: moment.Moment): void; + repersist(report: T, trade: Models.Trade): void; } export interface ILoadLatest extends IPersist { @@ -96,7 +96,7 @@ export class RepositoryPersister implements ILoadLatest { }; - public repersist = (report: T, tradeId: string, alloc?: number, _allocprice?: number) => { }; + public repersist = (report: T, trade: Models.Trade) => { }; public persist = (report: T) => { this._saver(report); @@ -200,16 +200,16 @@ export class Persister implements ILoadAll { return deferred.promise; }; - public repersist = (report: T, _tradeId: string, _alloc?: number, _allocprice?: number, _time?: moment.Moment) => { + public repersist = (report: T, trade: Models.Trade) => { this.collection.then(coll => { this._saver(report); if (_alloc<0) - coll.deleteOne({ tradeId: _tradeId }, err => { + coll.deleteOne({ tradeId: trade.tradeId }, err => { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); else - coll.updateOne({ tradeId: _tradeId }, { $set: { time: _time.format('Y-MM-DD HH:mm:ss'), alloc : _alloc, allocprice : _allocprice } }, err => { + coll.updateOne({ tradeId: trade.tradeId }, { $set: { time: trade.time.format('Y-MM-DD HH:mm:ss'), quantity : trade.quantity, value : trade.value, alloc : trade.alloc, allocprice : trade.allocprice } }, err => { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); From 77f973b19c7eeb296aae16012890e59eb810378c Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 26 Jul 2016 21:10:23 +0200 Subject: [PATCH 134/202] Fixed calcs. --- src/service/broker.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 992ed1ba7..c162bc63d 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -225,13 +225,14 @@ export class OrderBroker implements Interfaces.IOrderBroker { if (trade.quantity>0) { var exists = false; for(var i = 0;i Date: Tue, 26 Jul 2016 21:10:53 +0200 Subject: [PATCH 135/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 126b76f51..e256a5a9a 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -203,7 +203,7 @@ export class Persister implements ILoadAll { public repersist = (report: T, trade: Models.Trade) => { this.collection.then(coll => { this._saver(report); - if (_alloc<0) + if (trade._alloc<0) coll.deleteOne({ tradeId: trade.tradeId }, err => { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); From 87c93e2015f00797a0c479e411ac8f7490ce7e14 Mon Sep 17 00:00:00 2001 From: ctubio Date: Tue, 26 Jul 2016 21:11:24 +0200 Subject: [PATCH 136/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index e256a5a9a..6e89c9472 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -203,7 +203,7 @@ export class Persister implements ILoadAll { public repersist = (report: T, trade: Models.Trade) => { this.collection.then(coll => { this._saver(report); - if (trade._alloc<0) + if (trade.alloc<0) coll.deleteOne({ tradeId: trade.tradeId }, err => { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); From b6881534eb601187661edf47b5cade4af2086a1c Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 27 Jul 2016 00:01:01 +0200 Subject: [PATCH 137/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 6e89c9472..c6086d16b 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -209,7 +209,7 @@ export class Persister implements ILoadAll { this._log.error(err, "Unable to repersist", this._dbName, report); }); else - coll.updateOne({ tradeId: trade.tradeId }, { $set: { time: trade.time.format('Y-MM-DD HH:mm:ss'), quantity : trade.quantity, value : trade.value, alloc : trade.alloc, allocprice : trade.allocprice } }, err => { + coll.updateOne({ tradeId: trade.tradeId }, { $set: { time: (moment.isMoment(trade.time) ? trade.time.format('Y-MM-DD HH:mm:ss') : moment(trade.time).format('Y-MM-DD HH:mm:ss')), quantity : trade.quantity, value : trade.value, alloc : trade.alloc, allocprice : trade.allocprice } }, err => { if (err) this._log.error(err, "Unable to repersist", this._dbName, report); }); From 894f7c64d042a162431306b54b5ad10024d4b145 Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 27 Jul 2016 00:07:58 +0200 Subject: [PATCH 138/202] Fixed calcs. --- src/admin/trades.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index ca1b46e5d..c0b4acf05 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -99,7 +99,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri $scope.trade_statuses[i].alloc = t.alloc; $scope.trade_statuses[i].allocprice = t.allocprice; if ($scope.sound) { - var audio = new Audio('/a.wav'); + var audio = new Audio('/a.mp3'); audio.volume = 0.5; audio.play(); } @@ -109,7 +109,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri if (!exists) { $scope.trade_statuses.push(new DisplayTrade($scope, t)); if ($scope.sound) { - var audio = new Audio('/z.mp3'); + var audio = new Audio('/z.wav'); audio.volume = 0.5; audio.play(); } From a32a5e31247fb0209f1c6b1b2feadccdce68b072 Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 27 Jul 2016 00:30:18 +0200 Subject: [PATCH 139/202] Fixed calcs. --- src/service/broker.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/service/broker.ts b/src/service/broker.ts index c162bc63d..e8560cd9d 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -215,6 +215,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { this._trades[i].allocprice = ((allocQty*trade.price) + (this._trades[i].alloc*this._trades[i].allocprice)) / (this._trades[i].alloc+allocQty); this._trades[i].alloc += allocQty; trade.quantity -= allocQty; + trade.value = Math.abs(trade.price*trade.quantity); this._tradePublisher.publish(this._trades[i]); this._tradePersister.repersist(this._trades[i], this._trades[i]); break; From 80a2aec4b1a10900f8851cdf8b37466ddf88abc8 Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 27 Jul 2016 02:48:45 +0200 Subject: [PATCH 140/202] Fixed calcs. --- src/service/broker.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index e8560cd9d..36247e2c1 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -216,6 +216,8 @@ export class OrderBroker implements Interfaces.IOrderBroker { this._trades[i].alloc += allocQty; trade.quantity -= allocQty; trade.value = Math.abs(trade.price*trade.quantity); + if (this._trades[i].quantity<=this._trades[i].alloc) + this._trades[i].value = Math.abs(this._trades[i].price-this._trades[i].allocprice); this._tradePublisher.publish(this._trades[i]); this._tradePersister.repersist(this._trades[i], this._trades[i]); break; @@ -226,7 +228,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { if (trade.quantity>0) { var exists = false; for(var i = 0;ithis._trades[i].alloc) { exists = true; this._trades[i].time = trade.time; this._trades[i].quantity += trade.quantity; From 28dbd83ed9747a35b341028857fa635e9e3c7983 Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 27 Jul 2016 02:56:03 +0200 Subject: [PATCH 141/202] Fixed calcs. --- src/service/broker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 36247e2c1..8f979798e 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -217,7 +217,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { trade.quantity -= allocQty; trade.value = Math.abs(trade.price*trade.quantity); if (this._trades[i].quantity<=this._trades[i].alloc) - this._trades[i].value = Math.abs(this._trades[i].price-this._trades[i].allocprice); + this._trades[i].value = Math.abs((this._trades[i].quantity*this._trades[i].price)-(this._trades[i].alloc*this._trades[i].allocprice)); this._tradePublisher.publish(this._trades[i]); this._tradePersister.repersist(this._trades[i], this._trades[i]); break; From e885e4f84c85a69cbcddd74266759202efadbc64 Mon Sep 17 00:00:00 2001 From: ctubio Date: Wed, 27 Jul 2016 03:22:54 +0200 Subject: [PATCH 142/202] Fixed calcs. --- src/service/broker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 8f979798e..d1824a63a 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -97,7 +97,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { var lateCleans : {[id: string] : boolean} = {}; for(var i = 0;i= this._trades[i].quantity) { lateCleans[this._trades[i].tradeId] = true; } } From abd813e2f6fda285efd763cbf603135de070d0a8 Mon Sep 17 00:00:00 2001 From: ctubio Date: Thu, 28 Jul 2016 20:59:38 +0200 Subject: [PATCH 143/202] Fixed calcs. --- src/service/persister.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index c6086d16b..15308e702 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -168,6 +168,11 @@ export class Persister implements ILoadAll { public persist = (report: T) => { this.collection.then(coll => { this._saver(report); + if (this._dbName=="fv" || this._dbName=="md") || this._dbName=="tsv") + coll.deleteMany({ $where: "this.price > 0" }, err => { + if (err) + this._log.error(err, "Unable to deleteMany", this._dbName, report); + }); coll.insertOne(report, err => { if (err) this._log.error(err, "Unable to insert", this._dbName, report); @@ -206,7 +211,7 @@ export class Persister implements ILoadAll { if (trade.alloc<0) coll.deleteOne({ tradeId: trade.tradeId }, err => { if (err) - this._log.error(err, "Unable to repersist", this._dbName, report); + this._log.error(err, "Unable to deleteOne", this._dbName, report); }); else coll.updateOne({ tradeId: trade.tradeId }, { $set: { time: (moment.isMoment(trade.time) ? trade.time.format('Y-MM-DD HH:mm:ss') : moment(trade.time).format('Y-MM-DD HH:mm:ss')), quantity : trade.quantity, value : trade.value, alloc : trade.alloc, allocprice : trade.allocprice } }, err => { From 392319d5b9e5d815b8f127a328a60110bc0d2be2 Mon Sep 17 00:00:00 2001 From: ctubio Date: Thu, 28 Jul 2016 21:01:55 +0200 Subject: [PATCH 144/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 15308e702..4dca18005 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -168,7 +168,7 @@ export class Persister implements ILoadAll { public persist = (report: T) => { this.collection.then(coll => { this._saver(report); - if (this._dbName=="fv" || this._dbName=="md") || this._dbName=="tsv") + if (this._dbName=="fv" || this._dbName=="md" || this._dbName=="tsv") coll.deleteMany({ $where: "this.price > 0" }, err => { if (err) this._log.error(err, "Unable to deleteMany", this._dbName, report); From aa348bc7a795a73240bb714d971d01ac90072f07 Mon Sep 17 00:00:00 2001 From: ctubio Date: Thu, 28 Jul 2016 21:05:37 +0200 Subject: [PATCH 145/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 4dca18005..1d651c108 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -169,7 +169,7 @@ export class Persister implements ILoadAll { this.collection.then(coll => { this._saver(report); if (this._dbName=="fv" || this._dbName=="md" || this._dbName=="tsv") - coll.deleteMany({ $where: "this.price > 0" }, err => { + coll.deleteMany({ time: { $exists:true } }, err => { if (err) this._log.error(err, "Unable to deleteMany", this._dbName, report); }); From a3b3d76cb71c840674d5c329f96c3c6fc1734f6d Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 29 Jul 2016 01:00:42 +0200 Subject: [PATCH 146/202] Fixed calcs. --- src/service/broker.ts | 2 +- src/service/persister.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index d1824a63a..008a28621 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -408,7 +408,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { }); _cleanAllOrdersReciever.registerReceiver(o => { - this._log.info("handling cancel all orders request"); + this._log.info("handling clean all orders request"); this.cleanOpenOrders() .then(x => this._log.info("cleaned all ", x, " closed orders"), e => this._log.error(e, "error when cleaning all orders!")); diff --git a/src/service/persister.ts b/src/service/persister.ts index 1d651c108..5a3c7034d 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -187,7 +187,7 @@ export class Persister implements ILoadAll { { price: side==Models.Side.Bid?{ $gt: width+price }:{ $lt: price-width } }, { side: side==Models.Side.Bid?1:0 }, { $where: "this.quantity - this.alloc > 0" } - ] }).limit(10000).sort({ alloc: 1, price: side==Models.Side.Bid?1:-1 }) + ] }).limit(10000).project({ _id: 0 }).sort({ alloc: 1, price: side==Models.Side.Bid?1:-1 }) .toArray((err, arr) => { if (err) { deferred.reject(err); From bfc6bfbbdf0ebb9ffa4b7ec86405c9276bb5a4f9 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 29 Jul 2016 01:25:41 +0200 Subject: [PATCH 147/202] Fixed calcs. --- src/admin/trades.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index c0b4acf05..2c2f39d08 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -98,6 +98,8 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri $scope.trade_statuses[i].value = t.value; $scope.trade_statuses[i].alloc = t.alloc; $scope.trade_statuses[i].allocprice = t.allocprice; + if ($scope.trade_statuses[i].alloc >= $scope.trade_statuses[i].quantity) + $scope.trade_statuses[i].side = 'K'; if ($scope.sound) { var audio = new Audio('/a.mp3'); audio.volume = 0.5; From 886d39671f9769bc9964dd34f430d77351177f4f Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 29 Jul 2016 14:30:14 +0200 Subject: [PATCH 148/202] Fixed calcs. --- src/admin/trades.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 2c2f39d08..e47ea358a 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -29,7 +29,7 @@ class DisplayTrade { constructor($scope : TradesScope, public trade : Models.Trade) { this.tradeId = trade.tradeId; - this.side = trade.side === Models.Side.Ask ? "S" : "B"; + this.side = (this.alloc >= this.quantity) ? 'K' : (trade.side === Models.Side.Ask ? "S" : "B"); this.time = (moment.isMoment(trade.time) ? trade.time : moment(trade.time)); this.price = trade.price; this.quantity = trade.quantity; From fa9f0550876049bb6ba1818ca205ff85f24d5ffd Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 29 Jul 2016 14:32:23 +0200 Subject: [PATCH 149/202] Fixed calcs. --- src/admin/trades.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index e47ea358a..128658374 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -29,7 +29,7 @@ class DisplayTrade { constructor($scope : TradesScope, public trade : Models.Trade) { this.tradeId = trade.tradeId; - this.side = (this.alloc >= this.quantity) ? 'K' : (trade.side === Models.Side.Ask ? "S" : "B"); + this.side = (trade.alloc >= trade.quantity) ? 'K' : (trade.side === Models.Side.Ask ? "S" : "B"); this.time = (moment.isMoment(trade.time) ? trade.time : moment(trade.time)); this.price = trade.price; this.quantity = trade.quantity; From 65c2c2ac693546d144a0580bf9678260de432436 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 29 Jul 2016 20:12:31 +0200 Subject: [PATCH 150/202] Fixed calcs. --- src/service/broker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/broker.ts b/src/service/broker.ts index 008a28621..23313a100 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -97,7 +97,7 @@ export class OrderBroker implements Interfaces.IOrderBroker { var lateCleans : {[id: string] : boolean} = {}; for(var i = 0;i= this._trades[i].quantity) { + if (this._trades[i].alloc+0.0001 >= this._trades[i].quantity) { lateCleans[this._trades[i].tradeId] = true; } } From a0305304c8b1279ae57103002d2b0de3a15a2a67 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 29 Jul 2016 20:48:44 +0200 Subject: [PATCH 151/202] Fixed calcs. --- src/service/gateways/coinbase.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/gateways/coinbase.ts b/src/service/gateways/coinbase.ts index 4e298b111..e3c1654c1 100644 --- a/src/service/gateways/coinbase.ts +++ b/src/service/gateways/coinbase.ts @@ -540,7 +540,7 @@ class CoinbaseOrderEntryGateway implements Interfaces.IOrderEntryGateway { var t = this._timeProvider.utcNow(); if (ack == null || typeof ack.id === "undefined") { - this._log.warn("NO EXCHANGE ID PROVIDED FOR ORDER ID:", order.orderId, err, ack); + this._log.warn("WARNING FROM GATEWAY:", order.orderId, err, ack); } var msg = null; From 1a494771aba241a38bf799d4c53a974128a1c92a Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 29 Jul 2016 21:10:09 +0200 Subject: [PATCH 152/202] Fixed calcs. --- src/admin/trades.ts | 5 +++-- src/service/broker.ts | 9 ++++++++- src/static/audio/boom.mp3 | Bin 0 -> 3200 bytes src/static/audio/erang.mp3 | Bin 0 -> 46957 bytes 4 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 src/static/audio/boom.mp3 create mode 100644 src/static/audio/erang.mp3 diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 128658374..6722ed8f6 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -81,6 +81,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri }; var addTrade = t => { + //if (this._qlParamRepo.latest.mode === Models.QuotingMode.Boomerang) if (t.alloc<0) { for(var i = 0;i<$scope.trade_statuses.length;i++) { if ($scope.trade_statuses[i].tradeId==t.tradeId) { @@ -101,7 +102,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri if ($scope.trade_statuses[i].alloc >= $scope.trade_statuses[i].quantity) $scope.trade_statuses[i].side = 'K'; if ($scope.sound) { - var audio = new Audio('/a.mp3'); + var audio = new Audio('/erang.mp3'); audio.volume = 0.5; audio.play(); } @@ -111,7 +112,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri if (!exists) { $scope.trade_statuses.push(new DisplayTrade($scope, t)); if ($scope.sound) { - var audio = new Audio('/z.wav'); + var audio = new Audio('/boom.mp3'); audio.volume = 0.5; audio.play(); } diff --git a/src/service/broker.ts b/src/service/broker.ts index 23313a100..1e9bfd127 100644 --- a/src/service/broker.ts +++ b/src/service/broker.ts @@ -345,7 +345,14 @@ export class OrderBroker implements Interfaces.IOrderBroker { const trade = new Models.Trade(o.orderId+"."+o.version, o.time, o.exchange, o.pair, o.lastPrice, o.lastQuantity, o.side, value, o.liquidity, 0, 0, feeCharged); - this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrades => { this._reTrade(reTrades, trade); }); + if (this._qlParamRepo.latest.mode === Models.QuotingMode.Boomerang) + this._tradePersister.perfind(trade, trade.side, this._qlParamRepo.latest.width, trade.price).then(reTrades => { this._reTrade(reTrades, trade); }); + else { + this.Trade.trigger(trade); + this._tradePublisher.publish(trade); + this._tradePersister.persist(trade); + this._trades.push(trade); + } } }; diff --git a/src/static/audio/boom.mp3 b/src/static/audio/boom.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..e87126d810954273082bc3b2c86a2b896ec94fe0 GIT binary patch literal 3200 zcmeHIYfzI{8a@f(9^@8Xsv;pk04E@kM4_T2+$2IZBp{Tn8j6=l7lmq_u1lj?XtTzy))dC6x^6rUU@@Km{I^)d#*nKA7_dYq7 z=Y7uk-t&FDFn<$-VX`!q8y$iP0bjA9+qN!JUhLXM$`5BQQbB0cB7HYp@K1`v|M6yb z0CXoc|Du?%KW!gww8fVd{v{!y5n>~h(I#FP=R2%KweH20lwf8W5s zgQN=vPmFa4v8nE6Ib1|&H~0{3-T%nY@xKJnsqq6c)41)K@y z=?~7s!?$`RT9N4et|cUAatcYKoe6e?w#lDHXQ&ot1QhLJK4uQn#3gXooFvo8knjky zmv}s5aS^Hr|4N!%^^nF9nLK7(CD+pFA7+FVq_NU=+Y}Cz#W!WR{#KF9k^AIPPVg0S zR{2H^gQ-}_U9klv^PAkoq2C_8oLRSPw$uj6O}}6?Gtgg1cK2h+(^mO)7kH9L6VGQ` z{bm|%^0PxFU(cVCK9CD|K9pDi6O^Er&XwvLl<;`tjb`YDpN^sOTq57X(~cGl`tnkD zVZEx-qxgb)6<6)}NMGe$>M-sC85ilH&Zg%M{h*RU{|=|#w(rsb#@CogDW5lB5-B|T z99I+5wIdi{wg}Tv+47Y#3IWY0)h%y6d7AvCtDR;2U|z|4DLeZ<5%fyo@02{xIRIX< zJaW$3b{(D)z1Hiw9AKv20somYZL9*AE4+dEoy2e?&OlV;g3zXW{XNuWDWkRRnP*-wNWdN?|5~dQ;yD1K!2j0kiqE5rA&9tXe$zD1T%Z77F=h0ze$5Tr*=Fi==cvylfQ9NUmjTeZi?>w}`+S12q0sn}HCV#8 z087k|&HNEBbUCJz`8BIimJo4}Cw6yHb!A8GP=CxA$1L@Vwsu*i&qQL%d#&)axb5_U zbRo|D{hcdI?+`j)t~b!36-#Y5-G%RJK|L0`&m6!hB#mx;Q3{0Y0?C9S+5xYq!&jZ6 zKD(^_W=qE{;pOpE;;$%j*FRbD?>QDVwLa;tJ+k{P-|mV_xi1bnMVH;T%PG;2QmwO^ zOuOlAhnKl$(z)#QpjYTUE{%K<+3flK%+Lw|9Y-^Vj&)S>7L>@9{k1Z{=4J+7WWgYI z(b0f*u$E-Fx!n&wZe^i1WSNst9*kiR#vc+$ywyFEdowzt39pdLTT4E<{ukt569 z<|jlWenD-yeik9N{@K*_b;J2uW?ehOuaS7(&q4i=LJUxECXm$}L?si?1SX$((HZ0P zVbH>sy{jV5-q0O#UNjbHi$kI+lip)6&&KwsAcPynFT+hfX zyDEdVY01?a{FOo2_3tX_Cn}Z})kW+bJzl(-KNVOIfva{*z zEqIJ~vEDuCT6{Vz?3aR$kN4V&{nGX4t^Q-#=eLky!kM;rZwbIHT=7F}{93iNGyTW{ zvA2IZJ4g!-dnTS8m%?^@wwT@w`t6V7`T%grC2$U;@9}AcKFm+Hu{Qurw*nkbmgE!j zo~qq`-N{G|J>TNkEB)*bpa&R8w6>@&pO(Up0Cz+Drtx#fN2O&&)Gh$*@n(tPWpBj~ z3MLS}V+F^kN_NnaG7th_;~oX7XenUK?+fk5*)gv5G~)6Eoka6o=4^SMJ8?KYCz<6H zWZT0S0oX*5iA)?AH`FzbUe@7J*gigYw-Y{yz)QqXFf(7q>%CG#oE^ZatvOrG2}Gw- z@pf~rk~sIt9Yc>UOm)!^;m#&ggHi0D=3_&EZaIgKTytEYdsWE^R-sn}cS+`VV{z$* zKE3Q|DkkR^KV-h_3%>xvK2s$q7X?GthL9Rj;)~t8IUXy2R-lA@gpZ&suV6=#%A1wY zF#_|2DgRmT7gGHDCPVp-5iRVix!RQ9DE_AMnkToNS{(ic^DIifnFuU}|tVQW0Xw5F)+e+}9Zv%iW9<{MP{g0J_;eGXMYp literal 0 HcmV?d00001 diff --git a/src/static/audio/erang.mp3 b/src/static/audio/erang.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..694dd5aafe2be45d44f302720ac3a14459184d92 GIT binary patch literal 46957 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 I|KIz60lQrd+5i9m literal 0 HcmV?d00001 From d74649d5990387afc12f960e0b115b6f4bd4141a Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 29 Jul 2016 21:10:25 +0200 Subject: [PATCH 153/202] Fixed calcs. --- src/static/a.mp3 | Bin 46957 -> 0 bytes src/static/z.wav | Bin 7354 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/static/a.mp3 delete mode 100644 src/static/z.wav diff --git a/src/static/a.mp3 b/src/static/a.mp3 deleted file mode 100644 index 694dd5aafe2be45d44f302720ac3a14459184d92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46957 zcmeEtWpi6i(51}G%*-q^#>~tZGc$7xF;mRU%*@Qp42d0cjEU`-L2KuE_uKw~t$IhL z+jXy0rS6_N)2Dk{GUDtIfR90~t}Ma!E(zb?YL4y>X0pcK%%+a^r2lS6B`hq=P2F4p zpy$<(Zvy~w{|Pvwe-e!Gzgw!n|K$H(|JMWmZx6slLK>0c$~z4L0H2x$#tlFbwHH?Ls1 zn&B)dzdjIXC5(m`h6F$bKwSNj?Wg|KhXZgOesSUw5i41_bv2LMnP$&k_?0r2eNyG_LN0AJ>}uWn-*8AiuE z=Ae@~YMwFFKX8CF&y|qEzcIBkpfxvTUnnYnyN+Z|F`EpVSgdcL-9p;$r9{esng~sZ zs`mI{52II0auSX89{?b(X(TNKe*z+?X{X1!0W`>TkR7oAC~67PBF=n3&sjQG(AB-c z?@t~zUwWDHd>oo*KFxj4MuXN3`kf&}A1qm_3trE&r_OpCC1dQw=!;ftv)!#3?Scdn zizdfY4|s~24`*{0eV^^aA(_DvZ}{|Kep6k(5l&a zDfnQyaQpk}I$Q@K6z_a$OCRoxCN}gt#xu~-Q)A#EzJY<2U|AzYwQ|!=;wXM6-P9DJ zi*FA9dRVvLoNK#9Ql*Bsl{uN~gB$ddkJnZ%=u9l0K1~$kM|snobp2T(+vl08n>D%$ z$7x9hy;e}|y-1K)J)awA#B?gJV!v(Iqg;Nw{i4}iw1_Sz{pCzYr{1F}n}Sp-f1l0D z^LoI)O#RZwiQ2kuJVmVwy9o&!BOqDl0*E6e0wOVz;CLe1o$t+lk#`E1g)56?~4cLvi(&q{PdyQ)S3 zLu%ocMNVZ`2f4|MLf3b7L@C@`1|wm+06IuubH%e_ar$0pjuEpA9PfnNnwnAg7DK0wQQVi_z`l@J7!g zA>q4q)}Sy90nj~vy*nFS*W_Zx}Db6F@AxkTuq#sNpW7D zoKn}f`@V8dW$~#`wN-B1EOzaBEuTSEehz&vFN=^00Wtn+8d1X);Xx`cVfY+BYodgA zPIw4J2E2}W^Q8NmBP9B{g=NrdV~#4#^2td*0)zK3$(VL7w*9&pi-vLFPd&&l=qG7X z72j_wy{ZS5*@rhLRc+BRDJf(hR^`Y19u3HM1%8GXo9tE^@O`=|y~k3knL~>_m!B*R z-X1(If1b&vSj`B>y4W26+5KUG-ci16cQT5aL*Wg4-s0R2=sC&Ua4Of-c!rqKTZzUF zy>h&LVYvrAKljopMfZDKW$@|NC+xTcJRm+~<3RL*u9#EQ*~NjJ6u}&*!tdJRA6@-o zrqduWJt?BtTw&8A8BDy(Zxfv!tsvVyf*RFmt^}4eCD2-PQdT;C(ZHF_qD@7Q)WCG0 z3B$l~*ofR2)uKz0a48)$Nz0jS*=laQH0;}6pS{g$J+XG!m#bUpls`N3T5Y4Pzf_!C z0&Qo$w8iPY8g3Jg(S~A0JuYg${Z45tg$@x}!!|u(W;_l80}$Vgq=A(FZYF|WeLICc z!_39SC>O!xgYg9*6u_0lL<+oJk)AQ#KLCIj2!*638z4vuD4Uc~IA;Z5!6`75l_U)Y zR+#<0qlC4C_Mk17nP_Mb{=q7Ib0F$!786-U9zFRJo0>`tQ|mVh<&+8Z043xv@@W@N z7iaK2BVim22r!qBQ79{{B-#lC@kOXrF>cL#7IJkP_8iHB+6+bd+LFbz#2Jh4HKc-1 z2l8PPr3JUp2Ry5G2^{9Zl8Nd-9mohcIGEKd4Lq@nB^Rrrx8W1XMqYy0)d-gY6TziM z8C&h>?x&s@LF@nfXO0y!)SOF>xVMNGH$fTStUK2~9XvZxH5AV&Gkv2sNqRer)QzffrMv5YF zmxA5wG|}tvauYfc8t+!wbgw`0D%4%IRmb6)`?8vjJ4L3l^$j&eFqGWf$zSE2H&B75 zJ);9_rh%daOT;%*uP+RweU?$LFP@29t@iv#q&&a8#A+9RrPKBSV?%_8 z!xR`PbR#*{l_i5y5(*_S1e{P33XH{O8~1<7iI)H;CgLMgc-P$;&^tfdmjT^1M{qiA zG~Ir_irgAWd&qwd)aB(<-2A#riA_B5^-2)GFvn;MMJ@Am1)|r18 znO?MrC-sX-s*liNML%gE9Tz}|r=TL^kqn#%a(u>>w@6Z3a%m$K@MZvV z9e30FSIbpVlsrLswgiym_iAP^VFuEPLZPcFiIzw^C1H4IVlQ3Q7+p0+21{Kk!ut5< zL=KD~vdd*O<6C`IKrN&S`T1L6#NJ#Ti!=`x@}LZBh)m0B#?FSLU^U%2;W}j^82;iW zw)Pjn^ZqI^UE1ork)N8&$#`?P4rNjn*| z&;u?w(i*X%BZADZ*jvsTMgJUq?iRrJl1H=yof1$ z=54eIg!Z!7t7g0h(DyVDOf=F_nF0pQMdF=gDEjPVQIJnUf>yuguz?RDHF@7~e@f~% zjGAjykZ-cv(InPx=1#O8aqC*ewUtIFyAo5{bGO&lQEmNcK3T5TGAm-Z3HGPwP0+|V&6#4G;D<=y7R18ym%S-;P3>8(SYq3T>hkY+yYxR<=O~U)5qMNC5g;*< zgF|LhM0?~2Ep2X97d~%W@8K@X&xgDd(2oJD23Kta=ta0o@!!`O>EvH^+aGDQgu}%> z62ws624k1|&MsEf#OEciF;_HU^gAVh#>KHSpSiN}Ecxm* zUP5j@GZT1i>nENq*Dp8pX-~SH7rDK`{C?#j5E+xeBog?&R8LRe9Xw8pew(OJ?MzR( z;gb?epEtWLMzq1t{vv{;U!S~I*}Wc~UypMJ(Wxj66X<*`_c$c~W_BP3PhWH82K*xp zhX1Z0)bqodW4zmKx;))~&))=)gxucdMeAcX$h@gw?a+k*2Er-e{1vD7Y|y`!sA*xBd#x%rxz#zx95VV;(cK?~YmJKusCpC% zq%Df6cb_H)AI+{ivlU0f6@S5+Gi~bs3`A~&miF$gE0je~Wnd$|sy2*olUBuT-F)Wm zX;BE+ldhBD?%>(eo@VOsl}6oX7kLIf@4SMfE;n$~Rp6+$lI<1~6_9mEx$ZTC{>P&K z?5cj4Rkw{s_dFD(h64KLyF(y#t_X(mVH^0^w>5 zaksxyppJIxXX1JQv%+i_`h|!?Mn^;&i45+^0cYrqn>0(B9tDT8Q$ zCs&iOS82F(>|90Ej5rWN4L+kHp`(3VzojZqFlt28rrWG*gzr=;O=HZWOEcY7h~Nh7 z?|Qc;``7+foz3->meS7yH^S3GGv96m=69!H78it^bqBZEf4|w>VVU>*ZvPuRS8cQ1 z8hLS%&Nut^=Iqs{^*p!ppPeAkNzM|e?-m65&-{l_OLez$6H0Pgfat#k3hNR>2(S`n zk!_xaYk-sAO9-&6W+^Z~L%)NM-9>$tc*G(aP#!Je_1K4+OmXNTZ!^VQ;n-ELK~pgj zwb54E#x+3cy-qJCWvZ9W*Xw2`X#H5HQ$O z*_@+4M~y860%T z{4bF>-}=V>ufIXldQnMX*m)0J^$(=Z{ZI5n@e7gaKci4Tj0lt-WxZl9d7>Xm&E4Z0 znSZcz{BB`FJOOz{3iUO~E$l#ppx;FSMHE&bVccxmU@-yu!dmaw1p3$^R#qbXA{%k! zs03uwaFs3NOP;^1h55X<+N?@Bm4Hgm=7rO#%e2sOCXvuVd7fY2*~MCqhtS2h)vT7e z{34{8ZI`?PgJsSivZ>2D7^uUQ7YV%=DgUGM<6l|I^)`^ouG4UTRkN46qy+Z|03ZUP z3WJsJ1oOeut15}dssVV|2x1#yf#5Mbw7%~E!2Bqu0>CTLrbFAZ(yO7pF6Gi~lQlAs zVlZWqN|vgq#MUVSs~N|Akwi5WAb+NkO_XqCV1C1A7M$LYNml0M;>yoh3gPS`F$sou z$HdNJt3Zm0!62sBX~O5P;1*tg%20a_N*eZEF)(;H z13C!qlzmS=|K02@6t9fwn3MhDy{i#?MAi%BpCOpjGKFR`N!Y4XFbhyrXbr&(g~bMu z5Mq?6CQ;DUW=8JhxNjIEX6`@KC*F+<{;;o~jeTez@ zX}=5q{I6%mBe`hE9{|7#gvJk6_7F4z6i-DVkJSTkEnvjf9|FNQd8~X{ z{{X0J%o&165t0UQJ>#QMr#8C2tFNNRCDP3gK9gf%M9Z(DJU%-IRmtjwH|^&)aDEno z1!8)nFmo*E;3meOXKBBrRt{r8CaErlYv5pS2%#uCXrQSeNh(C`VcX}~O&BjJ<`K1o zaZ@VIV-;yiI&h;F$m>`5@2UxGI8csq%M1Q{R8n``OZHH0?DcsZ<}Y#=*XzY z#{_`MGM)RE6HB50Z?|?>Ws!sQj>bPBWb$(Xr}ym*bU~dFj{FE-*M7| zx1X5qnK-$cu6j7PnKH<{yb|wct^yQn_=jc=q}k50tXuk&ewY9LX?$rUp7Mk{k=~I9 z+;OjUj~!lRe|uu~ro(P7670JlX4rrBeOcO*wIm_AgenyKj_vtIWxBQYU$On)(m0;3 z1--CRyX8->S#yQ!Y63--KU_bkAEg(}(>h?&?Pa~yWx!LVaH!@-!{+w^01NU!C>)M9~H2Gk)T0X{O532icZXFaD0RWeUIgylei@nmz5M$!{^= zR_ssiy_V^m=PGNg7$yA^+gK-&S%UaGQJ2{jhvRY(YshdN)(&r9Q2#Cc~)d zt4S%>*0D|4%Somh>wxuTwso>D6s#ijHK}erkB8y&ka6u7*Nh^uAO(e<{w)V*uDaKo z@6r?W8G>$VL2vlelip@tsUlJkA5#GlBua&9 z(m&$b(Bf9|X+ydEoC&Hs6|I@Hn_1gf^ixBs9i7#zbHy6BGm9m|INu-lI_R#i*_)8k zPWi*Jny+(meJh1~ji3l8wg?r&dXHaQ-O{xv#O?M^dMa@cw=S#05y6=nhe!@uZCRl+ zp}q=l0(eIy1p4Wf?crcO!Sv|1CHeN1{9m^u!}OD+uC<)2v~}&ftlh)WN)V${Nwiw3 zCe&p#>w4M*0;FK%aU@aaw!E>s>PSy&S}+nS3-n6H0y+pRAMz)@$kY^D!hSf1H%b1_=r_Qs|9h&(Tq;8hc$Yj_S@extt)6-irj~Wb*m%K`xCZFU! z%W2`v7_^sYXB~{*Lo)*hzxSY1%C6?&cE_!+z&-aoJw~e;|8TwdR(%Hg_7CMR)&aPW z4j}FqMNJu?xH@0hs{C{ z$It^cdVVq&7{1t#mC6l)Rq<@wQ}3^C4jolC-^KDUBL~+8g4x|$$2*vQ)w(UO2a_a_ zNOP+$s=F-_!6G9}h8GPdJa{5i5#T61Q6_nZ@p;rQukSW2GyA6IYR@NkG!ePVC!v=T z)m92oYjJ5mC)iDGL72Y1efp04|2F;uCT`cnE zD|w4{vT~Dz&rR(XhkC=8PuG{9lQ%A+V9s{4oV|wIw2k%nHBJ~_b$3FAcxUzITG{H7 z`;ya#>FhMRCVjOShskDaE`G@F-8P~fsTTp1xjNMC-fVYd0RHJ&zOJ<}jN zOfc?YV39(sZ_?>ACwdfaz1X70SKt&XWxUm5iZWW$CFYGXFv1z&sq*{QU{BD3HLsLBD8F=^<*Ht{9pjtYH)(6SOXFhZ95deF_*6^_{9=x5N0mO3+P*6fD&!>w7 zf0d!^{a#DDRD1>FkfB`VABIJQReCfLLWMuykbQd4#jb9Oo6;(rv`zfGaz0zwJNd;E znkvG3whBY2HT5|ma?o~_(wfPlCA0U(&mFfW#@O1+tuk!JRRIA#uU66lbx|Xms5`2o zZ(L5D60Ggs6eG7GdvCuBRqM&UgL1HhzXi6{$YE@fh7GE*)4DUW9A~no`a`MYc?mY4 zr3E~RGlAY9&(_0(!_B2du-F1WCI#>V!($oNB`T9sIKV@I-4W44opxo}UTa|ljVGR| z>PIT4f9j5@l?uPA2~2lDz~yyvx4^K8JMq&~R)F@`tIhm&q1qkcmd2ds=bjsT8O?GY z*Kl3Yn&m2$lJM9~1inH{=&F@L$Oh0^*-UNj1TjmM>({5n1coS+Qs_lyXA0X_$zIHk zspH;? zz(6W(Gvj=VasM4iKwB8SH(U7yRU-xldx!w^UIs53CpN@okfsFP#N!xcdw{O4G{2E$ z5c6N~nSw}}(Mmrd8%F+^U77s4bY#iiC{Pr~ zlhkrX7A)^2y~1hOX=Yab#GKh3t(lAhOGk?CNTstpzctRW(u#=qmViFL7n7}4uKL16 z@{_~Q4ph$BzrCJk8tyf8N520Y`zGMOH{bHx|M#;+AILz;sha7x#%RITv2WOqDlp=Y zP3JG*WwN6(Q;I3J6={z>v6yIijDU4!2{%%@-U;mk07!vQtg2cd8(~0^tj*4aGysc9 z!=P+8Rn)KCw)uu8qKJ}>8xbCYJOeV&^e25Ormzti*z`~}1SW|SiVB@PhRU+C%(TMP z38kSfT!l1lV`}8Vx8jnT)I=#Ym6)p=jWiTnp6rE)<4yE+?-$Cw_4YU22pJA4iU@NNVwv#0@18c@<)O5g%LBR-lCSNoRCM zx(=l^7c!v9(od$J)aoP^krb6Ny+c8K9g)KeQPw;?Hov44Q57ei%nQm1ik8!h5cW=o z9^(YrmRLpmBtyu~%y0NAi%!xmaX~VvxT%~*#)m^y(yRGABiM}yFQ~(<{e&&(MlEbQ z$-$(|LJvRVbL8OT3Q*D_PM=kN0IPaGeUVd!lXSK@`B(na@%|JB6&xmk7OrK9ASlW{WdY9PHXR_?Ya9iZlbW4 z#O>vieJ?u(--C~ea;5~Dgoh*n^Y7}0uZ%Ayf_h)o=~dzLU%p^bv#$j+vZ-0N&y)JN znwh#-y2h2Ok&l73dUYg6y4LH-VOY7LyQ+Mi5TQW{vL+j`!S2waT##8;`($Jz!NDby zr@VupwB+?;2-8aV^Yu5KP{JSxtI|d`!(m8hVb6S(_yQH7QWen{ybPHLQnSE;=dUhr9+q0Kg7_PB&aRLos(6W9aM={I-s}@l8Rh;dbz{!8-d+ z^s&NI`*I6+BhI~ER0-5O4Jt6B~BP7veaV}CL&3h(;^H1Se*#k3_hP|%hpGwUxYczwufmj z0m~-}7@NPuP+2X%40}_KNiGpKC#PsUWfZKBUpQ-LD{ugcD*OR2m3+g0LTFfsRZB&+ zKQ(W0q-YEUF&ZK_iKjKFD-CKv>DiBb$#vhZ)o^?}ZX281d74W$^0}_{$=fVjDLr`a z4Fj{E1c(i1kCRYm@Imb9lZ^@2!z)+87wqW;5w~)~>;}6fszpgb^cZWwR#q#9v})26 z3v^>CE+I1dhgJ_jB`1H&_}ttstLH-!$xJ71;&Vd9yaBYzuC#D;Dr8m481=6o)VJWmc3Bm4#8qWkg7ua;~&a!-Ptx0!WNf75-nsRY2F>{o;ViZTGwBRo5T z;_eg#V^~rwo`HhCncK5fe4Gl#X-Fkcu2v9iAZ)Lx7F7S-&yQ@-PE!O8DeG1 z?7z~>4G^?+%S5JQl7||#x%jmt^7_M^p{MDsLr_}CaK|SS2w2DwR;266{K6GY9F6-? z7{fgwQ!r~-D9!RzEI0=AEpSRks4=xZe(5QWQ@S2I>|AAUEw1qqcTWw7wkR?XmHTKVVkJr!9|3Y7z<2 ze7?}}KfB|mB+A#;qMOecVwQ{JmM7Eg710jAT6{XAw0uw#;VrW<==T{Ql0fUxllm2g z>C(!FK026e(88xeR9S{kvxd5|D#A0neaLWxJCp1Uo(AFo;ej}BGm}=XP;yAXxz0VF z&J=|L?z00xpwqPJwj0o%t@eye>d~`9U^^TbOmKQk*rp`7Dv4MTcy}~7dz3<`ik-+ zQAz3#GR5`=Y+64gC(c=|wM+eUB8o&eRuR8>e6}a^m|#9o`aAu1R(^VVt!ydCvrtQp zKcpj*TIe2x0=Go#2bHg{phFZH2zciK=wkwb5xUA{Hh>P8(LzNC%i?I&c{Q?1DAHen zk1oB(T1u*xdVC26*buz)-#0vCkmFi;t|)!&gfqSK)f(AaO!qsOo62Klf3a z0OuX3gfdStiLW1#7s*90Ty8wfykuLGWiVIJMoVr zZS%^=qPg#J^{wyY$=$mA6=@=rcH-tz2&sq+_Ce7*$$`kv!jhsziyK*{s@U2$y z1h2G^Mn);tZ0w8Hu1fXbG&POUP#J*pvC*yDpOVuQ;;dOr|1R~X;mVVWnzK^!_WN&| z+roy7l?<|mht^OH?jYnD#iHSu-q)PLQU@v4F{5w{=9O8c zHmmtOp9g9Rd>6=vw|kecic*49t6fh#BP zJwTmI%k;e!VllbW&h1X9lR&S<*Nqw%OraTvTDf*cG*qOHMAG1_j# z52Nx99R_$$7VKoQOpLv>TrN({nC7dglQ?vafzFl}bq2oEebXXU-)P0~kuzjX)@w=Z zCr`pciZEPFzq;v_Z&Q<2>q27MA%mL*Kz>2*lga60yE*&vek)v*-&@#eYc*@gDpKCL zS#E!SgVqSwpQ;7V8`5OZ<81BYL?IIr%9EtTuywbx%VNgBId$`EbWRL>s9pjt32U7O zDOLE?6kryPa%ED@gUc$ZJ`)-}uBr$fY^^bU>bNgUtsZHB(y?y|wOv+Z!a-5^t}Cj7 z0GX?8781F(l1jT!8E1cnC!YIjrEX~25DSMrTq(=`s3|35wt8eIrUD9P!@io=g4>g< zZhMK{IwK?Rb@t&&bQIQogwR8VLMA?IeGIo`O<{6PQ|GL9h@$5E&&)VU@=*=lhqK19Okk(_!qA~Hcznl=K7GICf7LII6+Q;14( z$_nW#6|71&&1xBKZtfn9O7l#zAa0bKK=l~T&-g^jgi@panWE`lkftlm#cTkJ7Y`9w z;HzN@OP56gixJs&Da^nTZazFoBFA#0oT+ub%rVD8@Dx@**m&Q@1v^RYaKHQb`NHN*eKRk6NQJ5F<&HPwX44&=;hQi z#h6?PjpEF4i~{$PF_y{%57ogLUnRu*O9@LW1|FC=x|O&^p%4!)DohzUVB{*cEFa(O zL;h#8e<(D&oguGYSTNJHX!-OIflnj*UQ?3V8Ox$+@IhE8#^B^Hgzy-J(JgYnc6N_~ zh%l)L^p=szHYvJ->zJ5@=Kk)r$8hl22LMr3-Fc-Q6EBRd1QXu{Kl{S zRP9ZBkp=lcE}}hqBU=I&$r6!nppdP0`F?Z_>KZftPWzySA527YZ=TS_)GED2Iy`>O zFZ4~V`|7qy%>h36p3YP?gRrq%(}aaAjAH4U3&g%>ZD(hZ0-RTx9xM(28e+TB9e$1) z`e{r{!mXy)AiqPVP6+dV74{uetlWGsbEJp>6%=I_i60 zdzjB0q?Z!q@MTa_PSAs@{CKahH;j^Rbe%VgCStZCxqX1UVykVKL5E2ywsS9so7e3# zjXcSDll%E?)nyc)H1kFuY3bIG*EVjkIn$dor84c!RP6t96PkD-(x{o0ei ze%D}%T-jVa#eto&dme~ ztyFE%`r{TxRhJRVC7Be~rbBl$oLpl_l^l!X@i@7}8`RmEO%mAzq2V;y96067@)pnO z#vyK*=eej1SJ{kWM;gSLJQX%BKY4PGrTQeGVFx?!i50kSD~L->hLH#>Mn|T~RH!}E z*j`g8C%GYRX2VJc{Q&?n0F;#J^5cntQz4^Ij$mvpwuY}kHCxN#8jDR!m{8{wFo*_^ zg0=@9x}p)dM-HYZN6H5T;NnC{Lc=l2Gl=1Vw^t(Ia`?wD$)WvO9HL$f)uXdzA{AO5 zx|Uo;8xC9vn0x)FAWOG*T76lk&A?T2znAg_R@e?d3oQTpwwXW|!I8eUDNpC>+81|#qe+H2heN^3HxB3LHyAMC zHGUxNQ_cBX)EBJVTCFib?Mvm;q8ssh6BP>EPdldo6o^Ns0Fqc8tJj`p72)xTvrZe% zMjeYb+xN80QzxDFVG=9RIBY;27>V_ZIydDu&}8i=Z8mx8@^c6MQ*4YV;Z#G=*HGcd z{ur}h6B#~o<#scJPiB(lrLmJV%>wE&MDvB(lWX%@#MEZBsYBnH6TnKomFKHdflJSR z8!wf^FaMKz3@eW#(jg$P=n>ZaQY%9h6N7^TZ;Q-WpIe`v?_c@r8}$?p&{2)aYE6&5 z!YMClu6_uShbhpRmP7_)4)oR}xkq{vH+qmLLtziTU#V=ABx0h*kXnJ^Rk&)j@vH`X ztWw70#;vo7)2SPU)An#Ji=!v}j`r=_oMy9lp;&RL*`i0wT$W)fHGS%QI;Hgqk+ZUi zJ~z}o~MjG67sj=bv~8Q7V?hXkYl|ih0N+;c;W#yjwoGO-auxGH6Dv zkADDwGY~3Def>i4CuCPt=8yMgxZGeerHzU}gbd-6XHH?TU1@9RLv@ewX%=03=!P_< zp997&UgJA(1436lN%Gex2@-B5vB zp4L)F<|Nu29^OXITC$2bu->kiY(-4-@m(t82T5+epim?aS-6vU{}L65hM0C*3ps9H z3e4(nc@laK-r+F~<^AJNK<7)G;Rmhpe%Zl`-+lWWQOa~1@JoN9FhMB2|?}xWzrxKWw z+XTlm;}u4_1t!5jN0UZ&YIX7cd>nTcBIS8N_Bu)+M--7MOrS5EoQ_G#Od4Wli$I55 zn4}lsKvx6CD@O9rh-Ua*g$zhe;O3`bmHJCJsTP*WPxlG;4>wzQ86d7NAz2T+g48b3h#6iw>7ms!_wK;!EL2KBVD^fsgOgAdYvy5Dk^TE`QTK`wRlbU5fx0D^D*# zps4wXZ2CMA>CTuRkjJrqNkbx5kg$xgwLeS-U^Qy*?Dfdw@kY8?;PTN8RGYGEoo6;1 zm6*Fy$_MgF!;lC>HZ*k9>yW;e3t=Pj6{3SA;|K>nBVd|0Vsj`Y@Tst>z>bz@RZxC^ zwUd~HKG1LH8j}Gh6+2JnkytOCJrf@ukBkBXCsk%9kAg|cV*I-SxxmJW5qO-k0pUX0 zL_vO1L{J-@KZ;diAz@wGeaftkGeS0td$p-0oJG$>IXMiO#=%K5aV*&c+{MCc&?ge{ z8|hvECl;R!Cw!8GEmB>%D69h=ovU*0yk`aEVO0WPRH@nA2jU+900cs{2d!M12m|Vv zo_eO`0a(rfD&3<1a0ix3?%a5=c`F`FT%Jh?K(H_X^4i9sh(dD=jreQWFH`VUnhbkl z%QqO$z{5a&G;*lDh%A{FYP(45SUJjq>mmZwL0Yj?pC+n~MtOCzqr+?a85QOPt&-Ku zNFYE0HmL?r`ZMr8{dXdgYy z@?_Cn-WI~iLk{kulG2C|6W7|WG|=&WJ+xvZ%cm!Po1L&hP|87`6$@7(5o*pB^SG8W zJ{%4)t&%}*>0@7kLD&{`2~!v(;qjYj#7I^i3`5quSfx)r@1phu-BUMloK!?46Ypmi z^G4Dmwfdx-WMpJ)umns!9T(I9k{7_Xt9!JP?DhBYvTOcIvQ`CSa(l_ug%TKBq54Ly(41x(yV$S*=m3B z5|kwbL$kh&QJ94YbWoSaKpmr4S{as*h2Il*Oo|Io>GCjffSTA1hVR@Va>l{*@03my zX@>EY6`>WtnIc^|vjc(N2q22DTAaDsYgARISau}S!L4Xu*gUw`*meg)i=Q}M>QA9p zmYss=4+|OYc)DB7ykZBptWa>G$Cw(eCf$y}y%(J7En5T_sy~0x^=LDc?KLtiq@B?s zibMFJt;ru&so@(npWI0jj?)n|xm5sL`Kv+aE7U%)iMe0rA#MtGn@{Z3*R(43wN6j( zEZyA`=Uz!4hXm&Hm(TIdFI=lU_wOyI&+44eMaEr(iBtBATzg68iA-vu11ybIu z;*A+(ebFilLd~Kd{$aqEE8Y5@bbLW|aXeLDd&~=p_R!O^0XlreYk@w`{l$Vw*Pr$I>`yp(dLeieZ;P@u?ir z+|Uzv^2*1}lxO1n)=smoGDsfe3{m~;y9=MS%C5xvnIgdzhTKr`+E2t(@gswy;)H(Ne z%?%z+o=%?FOg8bIyizw8GIk7XE%7Sw_);9dGN6Rz?V%kFkst`nX)H^sT}Cw(a85Co zz>qriYGl*rYK@nvL~dx;BTNon)y(UG77Tu(dqGVCoS^L?cd|^b#cOBbRq>%#b*0>S(A{G&j4V(Cu+g#5vBM-pK$nz>FMItl}1 z%>qa)_4O?EOd2^LUe4;g#}iWFmd;u@g^nAXC|kmF&;sJTvdBW-L(`Ia9355a`ldbL z1UVj2q*sGs!nw1eN1fRYVWh*o2=PLhX>?hN3kvNrfKTO<0aMtV_zG{N&iwLRa5PnwEuHr3swK=CPdf@EE&lVJ%B5`*Z2nRRB7*$bY(L^(dK47Fy zc%y}p!XoHnV$hH_9KOZ2sgjW1hA)$_sM-pNguwT}50H8!vBO8GfhLV zLNsYUoJ45$SjZsY58M#)>NGSxKr_b>B~B=WK1NdNTp~0hvP%3#JA=VKQG6^vF)**p zh!`=Jo)o&oPJv!g5abk{HgzD}uVWH`q$vgi`=ZZkN`6Ymy9W@NXnb^rRHF&^0VcQW zTIl91Dj;-JG5z2YKFQF}S568oq!pWm7KQ-WMFgo1n3xU(FL~?#G5^E22RYr1`Gv|X z3YJaU1$rF|2)!|H0TBUx1uxty0%uCjNWz~w1=*PB`My=AO^(6jD9*iix>+o+iVr|Q z8Z5bVXU@|B091UX+5j+mU3QkP`66=TZbrm>{MC76igZN= z8u^e>6k5q3^!eEG=!8-NkUE-xG|{5uFA*i~2r$T~TNc|ylt z1#7Sg5Rga#2_Jfguy! ztpAcje)yvz`sAP^Rq!rpmgw^GPdVsmGL@9u_*x&Qs+aS@Q30?t97lc!2p<4=FN2Qj zYady@pRu215l;UM#4Rb&N`C=>x7U4~0|4OnF=;F8r1x$SG&#DypNh@MBNkFm`ZAU( z_wRB%+S%l0rjkgF*vRTBo%2JDn6pC4>Iu?UJ?gCLIHoUc`DZZ{$UNE-?T0VVAv9>6 z43@BW>WVo|)e`4?1zWaCz_O3bzGTVTyIrzPn>CgtEJ`Z1#HEq8r!~FhjZLJS?j$A=yOGt$t`||UjFlr>-UHTE68JG zf56aEfQDY*XpIq0tHvQ0low^CQapke=(t^~A&#u&EN#QyAum)Kr9gDLcyb?ZyjF-` zQqvg|}?ew4L50Ws~z zb-hmUKX*M%ZW9fTb}1s5CFg!Z3Ofh#HmGAl*qfZ(bpeh6EHfYnvZ9;Fm;VP zdRi3TnR5%lTQgJR@OR%-gns|+$ylxZbbZzto*%Un&Ys=0GZc`_iRM+{ATL|P#c8Wm zQd8aby`%ci>~H4HvBz!KR?pfqrht3F&lhuJ%*Q`K$2)TZ&%Lh1zllxJqsj}|jKfEC z%uttYi9Mn?5**}fTsfj1w~urORr6+6HKwBBGToq(Sd=bAg9EDjqjjw9?Ksp{0W;)RmFDZo6SPk)N?8&DYLaThwU$RW{!r zf%B_?R7$tO(`oMc{4<7W&60BYJ^x)RZh3#IW^F-lcY6S1>TT~?<%4@MZ|)Xvw9Mh$ zQwjGCG*s^`j8;t>OU;G;*74f$8k>m~Em9eI@{ozkDkuNADejc$Y;jcS#w;6oa=b`| zSEB#%iv$J-bq72oVt$iyh!p{!?Kmnkr)Yg9s{)EnjwX>o@D!L_)1aVQigxNB*P7j2=?0u^5R zyzlz{d~;XkuH0WUcg;R??m2s(!JDZ*x*K!)vH8~MBM-Q(kiDqTXwD$_R%6D`cb|qR zAYS;5oAE}P=IO{QW_*^UFC+;+^w|lgLD@PRYwo(m?BFw1&R_R#zgl=JdgorSFDv`n z!cHe}%xS(5acG(UgT&MQ2LC3}*_#2yR2jaK9OI*|U5`#QJ^>L-tF`JeMrhivcU}d~ zc?h7nz=3iLjO9F$Cec8pO68lBO4Eq8sTCJ5GPkWXyd&QrtVMW-ODo;XmHDm1KKMR8 z_$&uYou!i*I(&MzCXiF17ZqR;vO>gTcFTIKO>a2F|GKpNAeG?x~LsZwL_5nD4P{=9c@a1x}Lr~^`UXvx$#Bi=yWS@f5u&Y~= zHn{>r%XBmW)nKAnxu-GIl$Fk6K$E+Xi=7r;E*B!<^WY0x;^rdPuicWINQLQGT1E9$ zReJuK?b}~>``g5(+N3&-U%?L6+B(6}cYq6dKNQ@xTY7dOI51rFlAKw51@XSWlXDa6 zI=wkFW)&qH#h-B?vNfj_clW62g7FCm-II6 z5QrmOMgi_uI3T7oW{&dntlVVHu>**~<(qYq5&fmJwM4xo2`xhoF4pVKBaYf2uU`1# zZ)?3;_>%FtzTB@Zi7EV~5xli*9R&RAT?8D_)$iSzQ>vHIKGuUgVNU*O{tw{8h)r+f zK*|o0r-66QNJ#vhE@Onk{H8D`Mo zt!qMbu8;ydZO6wwpDME}&e|o)wU!sc@x6<^N~vR^l>Y!A7J-&$^j{RHQR6uiJOC)w z0BJuYM&Lw_aCGy3LuydeW>M}ZBywa#{T)Lf_#T{5nYXN*2fh`cZ}o(45Fa)`c-P)? z+A=H;Jl;Ld%iVRg;kdF?MF!a))1S(QkM)G#k;A~;T{|9Lgi`V!-GPy%?J3+IDLJZ_ zkE%gXj|B(A*7iYD*dE>$?doz1OQ%bc{hzbR@^{cad3Gz_%`c7i!Ha(`n)w;!;-UIY zNs>(#WoB~O4Z5HC#To~FjRf>lW6ibdD7-46wKOfauh`Ge4i1Tl*C?7G`q z;o0PBCzxvboKp6h(+t0dHcLr#)N6d^ zO4DQ-T7C6^+IwnwTB_@H**TGAEgeQez^_cF==&l(%`X&qYM7tV}lbA$Ym!S5*|K{&= zqiI|c&0JfNqhz>l2zg@8o;mv@`Fc0dxTr9%n91jWmwc@i=!|Ts6;7(oQRc3<#o6Ci z7Sv!Cmh~|1j+APm&i3LZ4z3KmrgMnc62} z|KAQUAG!8grWDXbDA_dG0ie|Pb$>`9MjmVC31=XdNB*}805qzJ0!k>1*>CAHa&>7) zL!DmXEneGQYxU(9I7S8v62#BpjE{sUyK>;`m%`MUD-Ek1OV72zO&SnQ2_0{R-0D+0 z!!0l?qO@amL*+{ysa}JEBvxIfXU4hPQe6OpZd1uS_oj9J*iryG&ild?ANH|M(j=w# z{wcn25hQ8Z*wq_s1*d~kR7s3dZ8SY{mT@D_ik^fcQugR^r_m4VUS1ZwwY9$}sq=HS=6O_Z z@{@Gn8Or0R^S!t0m09P;R|N%Mnm~DV%(rVxrQHUCnqYrU&i2MLg~d8-t#^Tz8nbMlKy?aHMXj2uF73!Jo|rm&NA9W;N$`Ht zbou1<0fm&kXb@2hx+aZ@fJPCa;mR38S(0o0q8`65xTK5Cxi? zS*y;pBiQ%(a8uLWQ{b%#8Ep6DXm@+!w;XgFly-zBoa6;_y8HC!>s_u;w>QDxr<)5n zILI%^{>8WTA>P0JPZEJY6UWQb*9M<{8`snT17G%fbyU!V*UOx}z-=$vDb;@_vp)T? zKe8ku(*J13lz-p?c&<7EK$4eEB;3cm_gMfGVU2Ps*g_}>mRHTv?F2Fz(O3@m!t`u} zkXP`O_eHd)BurBXZ3<&YBv^om($KNxG$P?$8Ib=c1mC3ogSr!hsu=E2#VEeNlOb6l-gWwM8bC6*lEe9O%LEzz~`Sczh8Th*MMS|oC zJv&?kQGM7ebuR3yXFAz*&u{&YjR3JcyW*bDx97p){R03x0If69==fO@*}=~_Fxvqz z@%44wiiabwHgWg!-^d??@H6jy-t@H!>I>R*U)nXLO3FvE_dD$^>q{K3ig8RsAtmAB z&F|%G07juZ;bs=*>j|rn)1nDCzD-ze989>^)o;C)bxXo7S&u@;>Fv#*Mn86%(RS&} z&xkDPDkf*I(HQfoPV_?W!Euun&vq9pEcqVI?kok%JMd)39J`(c#@19<)U* z)1xzf#?DvZ%#h7@Ei3p}D<-e*(=+Ac?<-hd+crCrDw$bx#Pig4-?-jBi6axm9LpHC zeHn25J_4Id+sx(VmQR=y(`U7TDJB?~m?%We4MmxJ^r zUNnCAav`Rk!=4Lw(5oXgP>e2zE8j6reyB{P>APcoJXaxI4rCpd#HyU~NLqK-?n}W@ zfU+i*4pKxL2RIOi2y0^`$`=_zf?RJ2uS5cZd|DxO}Dj<`zF9x*o+(>mQ()lCd0k0{Me_f&h5wq?A}M`|^6^7>~V7mGTZ z)@2XA3M_V0dhGzeaWpA5x#Q?@4OstHD?X2E%a}K>v)y?r@@8mjs+yJe8luy^)|~W` zz-Ua8(22SCzze=P9m)07QLo*x%%ynobi?x_{7CD=Y?jv28dmu~r4Le3$H`GnRCR7g zre38-(saRWvpsxA=rmfb$dyjPG9NE+x+Ao7j1*fQ0>nwQ`@1t?lt$~5Pny2chfO+%uGj0xM>G`l!aMKhc!t74 zJ?Ckd+YY4e&j)s%E`Js(`Ag@h#AchAyT5E;*7`2ACYX*gFFT;^Wfad;mL=fw^jAgh zsm{hRT16=^^)6=>N!{{)0T6)(GTwN4<^ok}^gSI*14s}i=C{vzfMm||*Cp=(U1-Ei z{z!*cU(aD0W`+QfoZsPmv z?-K{|a$3tdXAWngx#e0NUoNsv;Mmc55#nWvqv{`3sDg9y4jcVCXP{}dY&rNi_x@*A zm7~Z;iN;F#sZ zI5{1K_L*C+@Yd=z%hvc@An28O;Q@qJ9r8XNJ1@9Vt(NAqQix=4D3>O2bLyGu?~O+& zCl+S_wR`N&Nh5Stbn*hvmtkdmV(6je)7?VGDm#^juN16GNPyXh34*{U+3;f82$i^0*j8eW_(f)<=9T=>#cXNh;8a9SQthc3D>L~U#u#AI+Qj;5G;pPU`p0>_SQcXN=(8-q# ze1VgIPnAcu0S;Myd`bVfLoa43`dvusrOtwI9$FM>1IlKKhCUT#E6RuLEJ<1JmTp2U zOGN$Hbmi*g-`#%X*IXyJ6qSoz64dGj9cOBkLOG^d!F}3gdEZ_UjoZrVm7TLe9`aph z5}JuQL#J!Y!uoT}U%)Qh8Ux#|Pa0yeTzO8?mjt0^YI+3AOu6J(%45`xhIolAMCxUl zajP~i3td9x z?`Bt$u%WMNtdd>Y`ImGi5dgF0wZZ83eng_wAx8mA7Ca}KG=;J02$eiIV{u^~;mnCz zX4FT)RdxI%Q88k9>EX{enAP*s@(=97XrDcZM~}~i9GlcW%uNuHFkjzt7h~}I3v17= zK>zIk`~Y;lh*c}cQe;FcHEdQLVD^Y+od3)QrIkNhd5!|XK^SFaKG%oIRA|)&DqAmA zlzZz~t$~x0h=9$h;jDG-ubSm{nKbJz?GJT5`f2(g9CbFOZ~GjekP&3Ymr;~}GZtGT z7Gn1Hb$+E;P9-3cv{E`AE*@$5e&x`!6+A6*dhQ>}d~_#C6iJkg)nWtKES@b2S`&xU zd@C1rCQnwi3oB#7#yh2!eZ0_?^vB& zUP)Wa6&1jybZFirs_jBkUErYiq32{x!CiiHcy39QtMV9|4LehbWCFd$%7o7dlf zop^GPfH_m+vVekAO@4k(3ng1p^{Y?3BHBw6;hUXgR>L@yiP}nyi?rFr-+$`;;Xe6} zjPld>$4Nr^&pPG>uC8~(`9I9Is?%z4woO`m$t}hw=T7BT9?!Bqs4qCD6^4d_oyC4A zQJUELH2a3TpOKsn$Ctzm}Rl8TT z7-=WPgEWB*3we5;1m3nYM7}1!Rzsyr7OaLR8eBSVPW;cleN7Fy^Y}>DG*kp7`#d$w zAw`w2@peD2nt}r);jf=nhu|rItPIQT1A(l(JVZ5>;U{nY4f%iDAHk!$r;VD8k3;|c z|NS$$6x&tXX8W@1$&xmQk&$?r=P|=;os#7r0G`93ERY@V=R80ab|KG&G$4~s-@B&G zXgR9>;`WEkqqBjUli|BX$ZMyMUpdW^M-K&BL>>B*Wt_xw`2E?o?Zu-1agcIXm!}s2a zYJv*4SUfv0P_uQ+r;hACihez;(di9izU}>*lucwKlx+KV)Fsb1aX|dN&bHL1j+u#O zli2(x5-?d+Lcq*=w$cN6ZCwa>SJ~Y$X=1HUF>#B5ebd=45>0xG3{E4BDdG*A7)F~3 zhV+g^t*&ogcYPzGNQ}GB_3bLyT_+cMx8FUWeYNu=TDOjisFx1y=6hZMseQ~ZL(_FF zuiljEnj<(*75S&DPk%1EmQjB%33W8M@QpB#b~U~MbtP3oe4FOEF+BLFimIb(i{NdP zQCgM=!`0b71ZT^+ezt`wxO^BZQvv&=Aw_ea!}p+oCd5qbaqODJfK<``ntaMR9+gn4 zYS>SR#TOU>^4+&ZbX1mlJV+Pvm`_km~(XGHTOzyi@OhLljh78ygSbBYx27J%D2D6Qj4M z*D0F%$ZC`o7&_7#y-?QKM&f1rRk}f=j*tFZ*#fkn!5L7g6Oixe?&;vfI{Y_`G{s_M zdABpT@axlb!D67QdSGzcMbIJ!CK!(Jt7^hl(r+$=wdq&dXVP4Xszh|FnlyWDLX%rV zmRu$^39vvbhHmtod9nf#)n@8uAz*WgCJk)?Eld4kqyqM}>tsHDbCk=n4lq`}j^t!I zdx#MQ{*=mo;u0?U+&=(_0?__Gli@B>eFhrNie=LJwszBW8->V5Y56&Bf2j7vlyO8- znPz#3Cuw1ia5(hn(7~$$;D~@9^UWqZrewTppttL1j?7M6dPC~bBdBFaBV+M0>MVjcGbTM7e8WrJSJ8IkJ9Zqq$I0yT*Wn#*eUS-w&PvP# zts3<3k4xBg%zh8Fg6kf98FqePeQ?$@fBUf*ZM0R~zvGjWm!&{*M;dDXue0nY%I?X> zW+v^I%sB2=ogPEy6|Sw=Z30+#h<;@TvoI;ViCs}9n6J1!wHp@VwZCLRo0k)fP|D}w zX=P&uhF;E^jFHw|4Pxeyc}h1b?;LtsdV-6tGZ|L)n7n{0d;9zN@z1~a1Z;rPphV~F z-t9i>bU+kqf)9Y1Q4X5u%t-5W`fD^&_~I^dxXtYC*)Chxpx~Y&*-xo} z%OsqyMNZi1GzHZo3Ldy+6ZY%ZC2>`YC{4QFxo^L|7&N)+efS|4tM&8Ke5aKj!IS|M z7tf2b*0WN~cT)7z=1K&zAWCF&NF_xog$Lixnv0XOcZk_`d4H#8VolV9t^y%y3;uPTk0G*|1HxXNQP4IeB{oWPl~ln5@f!;3}XL$j<@0O9K8} zfqzTndS74z5FuJ3eJ_!~AWEy~w-_P0%fX1uN4+h@*2wb~2N}uX>nbO-30m0BdP=V^ zEHM@m`I%1X2fiVUP|p$jFp`{)WNc|zmGQf3`^x$hW0EU(k6oCJieD(*OAtOy?xQ?h z^r+vQMTgK9zRvFEILK~ zp6a7p)D4B31*V{KIV%-5*0%^OUD<56tO=cdo>%xJWxoj!XGWcZx+a-qZ@%d2CK?}* zWDAhN(-P^qWS3X+82@xWSx(~TI7c&nsiYCVMpfy{VkrLk%F%Am+`ZYdvt4-~i`JPY zDsz0o+^bsfXeHXti+{E)zRUu1KR1!s(eu^04P=uQE_nl)Vw40w*Vd|%Ze8DNM}XKL z5{qM1*K5>&w%AWNc@@{C8qUL<*w~`zV=7kn_e)}(mq=%HjzVXUENl5~&Gi`8?uzRQ z7S_!wgla6P3tN~|mh{EM%p~ueIQww8xYm!|w9)F4Dd*gaHq5(T^CYr4$tBswnCGSL zE0nBJGGp(C|1k{W;Z2?K>H-598On(pVq~W>sUn3a95+9jjA2)paZzgI#WdK^_Gst(C2mdsAMYvT;C6d}2~Aq{l+Gp1Dw3vr6@RwL?nw0W!; z%D%@j0O=qj&*KcLt-WvR9K4|1sRZR4Gndx^rCPngp92^}1CK~Be{Y!~gf~hHbf3jL zvwtu9?)q+A!dyCL57Y1X5(De37adtKi9kG^{XBi@hw{8Cl~4TYZ)5h@6S2XwLmV|J zEK{sx$LvZ=67xnuyhVfBDm|ZiHlu)4eCTaLIJ`^xh!GV?r+a8#mPXKwWg?h8C^(@s z%94d(u{9sfJocDY%fm9VY6=vZ-D;=%ityf)9+{~r_;FbJqC*4DnJ}N8jHx;8P4hmi zWvz+3!078$$-~2L;nVQs_@>q{QQou9#nPYu+H)QDB!9@{1W2ib79$)M-#>f8=wqMi z-j)v4&?dnpp|q~&AKTa~mGcGl!&aw?*}xSh%7b1`RstZjUS--0zVak=hZU-V!nZ{n zYO0nrY$QOx)Bvs4YIyC>~0Ym^8u~Cp?J9*?& zehrIRWdK>Kf&IYG2;!Cc`WGeNkV_-AHphBGz`1c+ev`wAXk3JfnB(hQRFW#u)t$@^ zXHy{~KuwY(As~2}HLN_7PPslxrR+u}as&^76C{Buolw9~n5zyb1BfYIBf;_Id6m!R zNZ4kvzCFQ~TG?%VX$panZFLrlt;Ut`lCI|*ww9Ut5{gQH`&CpY*VC7Lm_GI^3vYcM z(cNEjC1cO;1TbDxT>EYL4TqC{NUv5k%v#D$?}`L7ePl^FE<3pjl2H#P65O7dVM!1W ztOe65+1g3Ai@s*V6k|PV6n9ALK{!%d79Q!&+q}rx=c`Pwl;e75gGBd}I|Nd9 zDk6Tl$#c!AiuiMFeO7trcm2yF!+uHf9Z}Ix9n+YDNl#BN<(G}ixo`PY=4Jd9`=g1T zU9$FL3ulil%-eSz)aDX7VRQM-KbRgWfV!#QLBPP~S*q98ns7Z}BeW)83+wfbRI%oJ zgv?aON(LXL8UZC;Qz9a^&a4cCp4b-5QKX=ST<1z+mmdN=Tg)i zBr09}MO7uoqVE_USck1)UpvKfv%4j>(f9W!=hz&}Qhyu8=GBYkZ!Su_*)OF%GVM+K zW7#{YaLq{|)+mvKn*uintzWYE5lTDI|HlS>4ui@XuDRoe1r$sdG|5~bXIAN3SIbC4 zbL*eUaI&Exet9xC(BMNI-zu3+qj-0fif-?w=oX|I=fA2tt<|X#zJ$N!SS2O6Mq9F% zA2Krf{vPYqwlBO1to1cWppo=ww)1Ii)Y;pVCe}4zwdln<*0$3ao^qi$qd(TTB)7`{ zBs5)<|G1!0Lz(G@&i?hJV%)RUdwaTuQ^^Ee`9q-i>(}53vHoL{O#*xxuG*0rp1{@N5=9GMdcSBin>Bl8ngo!*u*a*A_2t1oijO9>vnQcz)%dvO z^om)chz%op+P>cxTG9;6w(u)5eBxgf7S5^~dA*qwf<bGgqc{yCbo5bx z`srZQJflPiwmqOMY2G#G+3meS@=pJ!zZX@V8QF!wdprQbR`%uEs8%_b1642h>CN z^J16oqSCrEZeAMR!&8R25BwS3o_*%j;B?N;Pq=SEX{6z{MZk-E^PJzep0@>aTo~Tj zJBB@9?(6MXusmYkn^9v%WWzC&rtZaflWp)LuEFdgLGh}3s(8i|ECkHp^EApW0hhzo zdeS7tygq{ov;#@t-1}% zSG~@55^*mG(JATL$(TOmB+(+nrDfevO_zwR3)+A4mZr+mrfFEp2-BRnc<*c>I;h3& z7qn+*om#X($7tVh>;*xE2I=Y2Est)QOCP97>M}3dXKB4M;ilYFd-v(-drv+BRB-N* z2#jEH{BX%2&y^J$^T)7E)%LZ*4hXq{4Wt;NK2O5D#O}wKP_8eB%7pn)rWhVmn1Dw7 z<(GZAK2%T}Ut{d>eJ~M`X6Yux&+hDa78X+hM;KCPjTI~VCHd8R9B#jUQ#obrYKC3A%{%6_zR1cJgwc&Y1MROyL}!PgEw5N+ zgl}ASLz!>Ai^y~_g*`O*Bk@QBBO%7*;}}cdH*BEGkiEw^trEqT6}Grph&iX5zOm1T z)VScOWTo^R9#Qqy$2l7Oa)ZU)*ek^qu<<1eBtLY+vWZ2jRwdv|0~Yvx^$*hv3Xi|H zv)kdW-c4X8bqlF1<12cmgg4`-JnQE}+nYNn*x&r9*fan~~(l6wlI)_(kYpF=@1cGP|LSjFOb#U4m z-Eyo90vEbBGg}$NdXKR}=n1B>=SGH*v3J%JM`gW$a#0KqAY6Jrs}839m7QINN}KEo=_=d}O)Di^j*)uU2jEw&xReuPcyKj`pxWmtKtSFNBFEositQKyF z8+mEme0{w1GID)Jp9n$#VU({B%Q%2l^!395V@1@Rn6(mJ2)1J6YDp@ds19X zW#ujv113{EpfQR#5HNxwh%SYPbC_X>j0&)^O{X+0sA@0z@W^@^M~Ffap|}uF2pD#7 z?PLAr6v0l2+l5Ywg%km>vEz5~YygXtX0kb?;xUVZqNmV_aZv#BANTwbRFYDCSfvZv z@AU|2f)NEct)6*TgxWk8osb{960DJ=+{xVh@^5Fxu2Dr9%d43gKL@j-lPb3anYAa! zMx|dr=)GY+5T{IcP_Ik0iNX`oFMOW+Q}^@l{tY@mBx+azJFAypN6@u5Y_F_59W`Mo zOOUwxxnh4RF={hZ?uCm?{>Y|nsgo41R}>elGeR!XsTJL1XbK~1Jxn)*@Rqreas@JX z5*ZeiJLHoUaNtS0TYAlafmz3@%BI^bKPna%XEOv?F}6mo6Uo>NGorSAW+z%oJ7&?5 z3e=ml&JnBO&*RU9Km7&a5i?;xKp)Zc>936Y8TT`J7O_%ku13({_4Sp640Tswo2 z<09YiJ9tH=Q{P5ZMF_A?Pn;I!Gq9p^vSgm@&f%qw@?pD}vCmi<)d6$ql=IGL_km5T zQy_?X8$MZ^@*cTz-!3-UIW*~QrQy`9qgE>EjKlHmi)V@(Fe9T~{pU|N87LWtQw!Gy4sFiLnc}_k9;FsFZ zdH{=MBZ2zcAM|}RIlE18#_+_gt2((t243?{+CNIw2_rvvQo5ZwAB^gkFGs~1kBZ$N zjPt6ii+Y~45qoE=#1a7?RI3A81LjN*`wDV^Pa0JMR8C)|JIGwC#C#^gv)T&G5>G-! zIPTYL?F3!cJ8uf5N*7Gsn#5M1oxAda+ns^#oF3s)574V2^Qxwg;r}YDHGj>yo<8c{ zpgd~K*%aZMZGB7&H_2&MU+vpZQzn01JvsAO274h0_e5vLxo|@urm0$HXoV&HUdcl8S#DH_b#N&Iw)>@q1Tav|< zY-`Nb`VS~f1=F1}xZP*gO|c%Qz1rFJYfRm&)|yU6yy5j{CF_v$J09a9O+3w^C+mf; zPfxy`Gr4^41@mT;^#$1a1>M6G7|w2%M0dQlJYe!@o16v4sJvL=7Vi^*4i}5|!;zZX z>DfzAT}2<+dGz3n(?pYi0Sc7buI9Wl&S^z0C1r6FHUF1VC~n_x?Z|yp<*+`KBdBoj za>+$2e|P2G=6&uhqJ%K(UuFsVmG_u&WoN$7`HPZ1< zbLNI4hn2&^Q1PLclti8 zzIvVZX~xiy^N30A>D+T_r)zV^i!d%uot#EZ!=kGeJcinKQ&9X}s%K3q>zbIKvJ>^A z8B9~UUz>bOT&Dck+#}0M)eLq5)*(m)&)SHIkP(mRqXvjVN5riq+h36FSsO5M#%yt{ zAL7~B-`E|XIT6ix9Heed&;J9!a~M<@vhI5EDyW__bWVn^c8w$1YE{w_QYF@V5U7d@){W=TnAylL)ePK)9#8_e#`I3)NlK>Crh?Kbs2D*oRVK3R$=!? z$Wl%P=X~&z@=Wd7LmLxR0L10F?U_gCfsk>|Ru z)X}^PQzv-AIy~g15m+1=ZUxlx67%TV0;Wd@5ZJ_*W@?nqYXOf}FqLb}lTbLYoqmKR zMpV0b!s0`D1bF+xi~?7PNXJV_b)bHoZnl_3P}RJtsYdkF;vjmLEFDh{;qPq$&g{tz zWRz(W;PoQn_;l=UYD-BY?qWI;El8%NQ>=}rD!7q2SvQPLRaezPPV&eIl#m5&?1&{| z&-&ZF0Zl|Sx!dJ6k|LNb`3Psp5x}RX*__qJ8Qv;V&t9G`Fs(eM0zUs%jLkIP^g*?; zK_w!ZF4E#LEbwr~{!6`?wcy%WU>ui_6?1#7-Ta60&>ai`k|{sZKey=aZ0Yq!7h5J0 zN}+K*2y41d+gK%JoFdjOW?qW1wVcgY*w5z`d728iH=ZV(C3acb34;vpMtY|O`^RQ7 zKd=>*oO>=g*mXAD6`BV=@sod2vehe7WCxXTO!l2t4)HyGj{hUC%n0uI&~*-k15gk$ zX!?g-GZnXsN}EOmoBO~_PrMoKgk!T@x9Tc`AC%Z?CwfmprYTb>4V-V}L^Hk(I=IGN zh=$20m5FL}Bpfs6Lmb7-(_8<#omC z)4YG$MLXE~XS&6&&hU+RwwrNL?+sS@!rwZegLg3~!XDps_)tK(Z8Ep%4O%A|pu9kP zrwRTK0EQ80R0amF7oLZ;INP2wm(3rqyM?%gWRu%Pj(y{t^TG1S^)a!W2?n-Tr6!$Y zFn{r~c?0!qs4h)&wo6b&>Eu~{NO7XI1^c|RXtVa!3zK>Z@9b`9KEiNpw!+qs!?Nho zqor8s4R>3yc6X!E%KU43-pLrsEfdO!4{J{pOIE6~NcZ@$vnDycupR1Yqr6WaSo6VJf_rS5mIYfu-$hoCOWHP)BAIuQVm_XNZiYGUo2I!5BpTt8S0B~FU5za2!xV5X>=2~}4L zhQb}my|~{0;nXopaH`Ty?{wPf=*jAxndLKSEQW&beEnK!DS7Q+VGILhMg$CU@*!C- zbv)4c89)M}B*rHn9D7BRYo@Vy#S+hOR5N9K-g0BPWfkI%g{AeeJV0xI6sNe1|LkWD zp2LqKp5CRLh3&{}r`Q1Mg4FdREB(!~UXWMHgDp$ik@Knq@^vB(0n_GkDo^BQFK2PD za9mUm1!ss{+lwfqRL%gmBDg4fPt;mS!-+ z%C5*SR130ZMH6~!hwvQTKAj^k8|-9a4`nNfcEYaa7_Fh_Zilg|1+4x902cr)$`ImC zU~Bl+tzO$UZ6MRtNa^JHh$Jr#m$2Kx9ye zjrkb7n1ygEQw@cJ*>`hhwws=U| z;8dv?Hl?pBxFXY4&LgDg8S-wzNe=rr)%FMxA}^RO?jLb{FFCI|#nsETt$VuD)G# z5;)P>_i;UJEXH8ioFhsDdX#sb62IOz8%3E_>!gmXccNET*2gX6Orrw;=T5HNN+85L zW;luC8V7^wUSZ`(^ddvMZQ#USzBx%#SKRydPH?920!c4}Obwcdj35nls6*O^gIaLv zX_gLlN4ZnzNKTd#Fb2aMBf(f4qr*ZuRw(uX`KDV;QOUQ2zS&SY+^G!f{KfLw_;3ovC; zN_Xr`ka4W|MCY#wEURv<7=AB^czL^&CEQpu>Np9_LOHA_NVCAL36N2X%^t*(s)Lg( z!TKd&FP)48!z@(Mc$Kpwfkc&_x6H>RYGn(rzOnb|dGBB0oI~esY(O1{UB?JC04~JB%CLN@T&k>n zGP|vs1$Og;S80LY--#N>#o?mu$LP9cRKh9WLEkH@|rz)gQ#lWuA_? z7u_4X^-Rlb(!6@zr*3KL8SA|1Dt_Dz1Zx3Si&Z(5RmgK`8j$!$?kqomy5M0o8Cxu#SWt zsC5_BklebLE30&usT#|VYBa%POZkRJl?_KpV=xi=t59WrLWg2a916hiH^Ih|L``AEQ-YRBth3QDCY2rDT$xx{Ek1O;}CrK{lF5?Gz}i|Z~5iv5!# zRb5}v=+MC5W%I>%PbC~s&Fui$m9BzWg6ITBkc_N;7V0KhMcOL6`F2(qya&9!7^wY&`G7Y- z9h0Thp3`R5w(^y7Y=4iv$3w&Y>NeLc_{g7O~n@f)=f6ve9E>)bNb7V z+SZf{1>Xqv4LcLq117JzVQ@_L3MIRi5vL8e!jOl#LC>FejS}91C_`Q=88c#kw@5!A zu>sk(BmU^U>G6#fB7d`Y0rIjb^OG>siX&SzI`8q8m4HaX=`6J9)P75{7g){mGT>_R zHWHhGU?}HGO@d|-C%I${ayIuvxPUga*1V+g<#$dWB@Bob>G{Z$@S@6PY1A*nKKV>&(BEb2j%nCY=9A%P;1^PMwlXBl<2JZc-tC^9d z&#%{>^xGyO*XO8Jc0Lz*D7+xL&D(834foFb4dYqj@>k1X-YFb{``Eu!9CzkaI zx~6N;!$ZKrr>%!6BbMRS$!&@dA8zFzu=yzsg8lHh7GC$O1Qd&$bO8cxaeYEz z0avS$R73s-Yq7@ZW@o)N&93i>h+ZQp?CAtVxM{6jUE8mTTFnj-!s+*&M!A}`m(6*6 zVKZ-+I>*agrMr&EIRyqKNe6ZI$|^gG85%G&5401CSl0wh^Nq9A?U_$Ww2z8a(6SF` z+sInsUasrUqBS09aloZxj!-CZqMwt^bNu0%z5Uue{q{7|YSku%9LwXI0$e+&Z^!FC zntPALfDX{8n7*l_epGQM8JC0Oab!~Srf#a!vgVT;w8Fyu(#V;s|_84$HI zWjkYDvRaje<=BJ=T%+D(SiI3mSwyi;#-|mDI0x zwRsZOSABeF7?`dwAsny%+p~GQ11EuXBH2FxJ)fC-8K{Kt!&XjII`hS)pj2RXlCUo^ zxroNll2Xs}abnY9J=2$D!b}-%{R~yCRz}zBJ9Z`t{nJ_5xBd?RHURYI7!9ZAOz`44 zLTlCrz^H@A6_NtL3FbXA5Q+d)J+tk1TTB$Zhn~uljQR{BT@?4L^Vk7+%6IVeXAvmC zadvG>FT)-epJ7@d)J#k+rCdZsYC7}jwHnV(nwR6Xrv+ zkGo`oZySDQ{>+B{UegkMJE(dwl(*tuI0{_|*_kQ&)jXyF#tgLf=zYrR|H17o_s**X zEACT*c@yd|@xt*_@$c5@W6Bq%&O5I^jayQEd2NY1(_Y%`+1ztpvWoxb)5dw;CXZls`g8(!#-zS2k5%MR902g9)TliINM=Hs7Hmafls6>Xc5@-Cs!4CMH6;4 zZy2||qR<&Q{K9Rcg~*YYBoY@gxzoQx9`4w7d+No%iaX~yQ=(37#O|hhsPb4B{fB%_ z#L_@#th9MiOR+qoA=?fDJL`Ut>MqqQR0K5#m6SEum5e`XtO{pB<5`G8p%(q-^p4sa zM%!F~7{?LSTE~rda?W?c+wF(ZWJ<%fThR|pGt_RU8bbxN64IBtGtMvkaocwLA7{ef zNIksn{QYk+KMRKVTXI5dAOG0T6#kauIse~>)@f4i+mnUw>TM=$laSSM-{b&ASbmh~ zcA~Dnwhrxp2x!Li!{;ZUUstTlQ*>v|tD87WasQ^W`c%B1FvC5M>cKgq3^WH!cRIcvYs*`QiFed@^$dT^ytLy3_7RnZ!HUNomo3r<7d(8b=}L1X9cafb&QVf1iE=FiIMiW!hOXSFZ5QeXH4xomc#YXbO8l1LU30-?fUCRZZ)u z2IEcz?keq7NpEBIY3ASC&Mp|)V}-`dR0-<$b}X%EFcW98q%`StfHV-IN%F3NP>}LS zyP{{=1t_FbpO~cjS0H{9eo6S#I?@=nqDv$z@u!yX=S90rqvIL$%kzm*$fsQg6oPy+ z5t-{lRzJDalt2fYgE%?e2f+H(a8f%SB()DvYfjB*SQAyZ4FqTjN`bznwFM1SdM0%q zTcWS3DLs0IWB5FcawD|I=?8GPNXAvxBtb3_Wk`$xd0Lc$390%JjD{+NW_~dvJ?zK% z-S#vtYP)MWljf*d{mZ+EXR}Yf3|~Kd4)^#A)HtTnhZ0F4EMDMz4+wPaC-{y7Nw8ae zO8?~D(7bo^^E zDOvxw1IYNPo)ggB%)&Nz9S;W0w9ly;2VTtBNgs$*EB0bI`0Z1q3(I5o?4)j1rUUYJ z$z`v^ziLizFt_K4Y$Xpr%$%H0*0F!YbaQhv%PJq#b4>c--_@4@kB-eI`gnboPvEHm zmLic_pZ>YB)urBW4K;ekr+!BLu$-q{c|C)mjLDMXdP`1y+#R%xjw)z%e?FY6W+bG= ztWP8(MEtI;DG@U76HIR9>1NOQEor3t^;pg=>t|!k(+Ez20I_TJ8;knQ;jWS2DcsreYPP~`G(CZ3B znc~q35@L<7@VhjPGXGN8Mw7h*Ukqy65xLaXES{2O{jTWQfU{mpGQMI?OuL3PG8dvm zs#m7bYw2mRhJxMDyszT*;&ZK#R21zVGc(QYc@>TkP4-0+dLU;5#}T*aCf-A~?dyhu zb=b$A%1=#OgIWEthQwS#^q}&kSAV-%yMrYgxev(KoA$FfbC*5vW|4k?A|*E@@xBH0 z7Q7!8$s67`PM_7XZNutLN?P2OcDXDT7jkelm8lbulQxwTtnzRq zsd2at1tF^_#|ZSiU#uUvgyK5D)ACAGPAP!}*xBmWpG$aIi4*j7r9E{5NmuQ>GK!Wo z`nflU(^Xu6C#&5WHc=dX>Q_m-!dn#Du6_C5!eF2o=$VY8$w&H{SP7skY#itA*=>j~ zQgAHM`7?Fkf7&~*s3z8TjY|{h5J;p7NRbjWKtPJH=`EB12_hh3Aksx?RxI=qT7XbQ zX^A8ulmMX#s8j<|3|$mOKxt87gIln0viCkW=jQyqI%^#lGi%LvG0(-kzjvNBYi7;& zJ&!|oGrX^p=BH4G9K#GNZUiJC((QO>h#vClx71X+AgJuV?U|=Db-CLULqz0|XdGVo zS@r|L1?t9tAK9hY{p&I&vgIrF{c^ykl(u_62I7;jK2iEF6FVoA^KbHxkT!kurR^U3cuznfgAw5-}!=->@@?P?%-8N zy)qc$QSQ}z&1QVXAySvGSM4U=-#_BHp7nKF5LeDH%x)?qYx-d(q34qy?Wd7ke+qz= zJ0c@W7S}7*%M{C=jM+Z#&`w6zBvIRsX?*Mb_NHNA!>r3n_1akOpOHE!e4>SZ8v99^ zCMKaR>!SMRPuq$S%2D<_hmQ(Q4(X&2eQiy}Si<-QAA_VMcvZCuisjWZ;51lMEI(mB{51`s>*|Y7>{Sw28;+WG}og4 z0_KqWnj9b%@) zCS2nBs(evXfso<){MiRPYfE!08AIdbx^oxe9v$1zbCUH)zb=}c0mg|+$w-q_fS^)5 zhYeac2XV=4lg{5j1Wp!!^Pq+7njf;@Pd4A-PbE|Ilq@u$2q(wzo7Fc$aJHALWkWs+ z&v*s7SX@keBO?z^Ni)rq0v65gT*?_L0r4Bm37$;qZr_D}*mFu<@a+4eGI9D-M+vaH zZsqEkunO)rQ+?dGnc3`^rKl%rwxRVl3juck%}`~O$3=zvb*G|VUQ#GIdGA?pwX62a4^cO9h-NMsiexY7m_L( zx2P@oSU2M(0LWHFAUAU`nf+ag&4X=+R~jT0q8_;LNUB@$1Fz`;$QH#>2D@ zFjvVZ7T0onT|G+T9v*yoHr!pKOf;j9bOf6h58siLg0!c*NKQJv({GLJS$6USPPYOR z{u-!GB_U3kZzwjOcCzJh&N3-?F_Em>rG1e^vWf2q+?{1~R9!55x0d9}zE$(iuS3t!6haQU^d5d zk-Ks)nI$>C_^ysV3q^Q9F}FZ7GzRTc)2c5A`cIg|gY z>#e37gM&**%dtGoXg)U1YPe>pyT?IY^PGzD7N@URjON(F*;d}2%ieq!6!L}V57*H(PF=6>F;t(;Vpm}(t$b%@0?dOAAtd3UQwiw^ zM;yazZEQqYSTBr}Fb^AaEgl91(iet-Y1zf472ZCS6%W7Qu|_{fIPy5b7gsEs-N#pQ zT(n5j41Dcx0~p^q=yk1ojsHma)77srM$0v>fiQK7(H+2jm4zrAsBNhqK;brhLHbMz zcf;Z|OkZ>O>=ai=)BaM~4w=~9+0}u@6=u!xzBs);q%pP9$hggHq$;+o`|sul5wT4g zDrPS3tO>kF{L;AM8Sr+IBUpL}*6uAUEfMp`)XGROni%%td1ajF&C{?-&_pQq`Jla; zxLs3kGw9e4a_0D>iYYGk4#5*I*YQGV#~ zm;IthFA{mca?IN8h1}(-A+PeX(NQ_Xn^IS@rU`4UrP%LqIO3S&v_f;TaQL)Lp|{L9 zh)J7`>6{H1M9l~m6@e7vU*$#3-y zKZC~EDrVh%&0XM|mGJ#%O;a{7DeR)UF4Jt8dfO9*U9YURU1-($if)fAHBqC;=Bh_m z@?tFciKw0g>mdSQ5Gr@~Dbv=dr&4_|0TrkgC(7X(9_XcTk$n+$1NzQ=fLf3+`#ipkb5)Q&w3yJpASrStq%X?jTT_{t zS!ZpP^-rdu%&0@Z0(N>aJ4{?NDQ|}D{_cpT(bVQmtVPX8W zOL4per@??ozazD4klI}zq^d@VX6YI}wp$QMU)TLg4z?=LClm)qFg zLN|icMOEq0mQjv}-d$`JkKP>5>&`lk$X)-5Pjra?vw`2Wr?RZj0$hIsZbZoY{J@H! z6JL;@pP8aklOD*B%;U=tD?Hm3etjapB4ulZho=@4LeJMuoESSdqdd;$$P^7*GZKS#`ZK&wy0)#)G6uLbN|27s_s|4?#*Z>4#5 z;PgH3Gww+uX*6#y<0u!&v7W`{k6Y>~eCfQEC!_kgtuR7HA_e#?q=~ljs{*A5)$)*V z=^Vr;6Qz6@G<-CmBWiR0R>S1`kz%{ewN|E!lrFP6FL0Y7@cb$=GG;CPG9P?(n6g9L z>!@*OecAif?PR=)S9Y(tJVMc)!dO&xVev?$YM zB0|ekdTGp4%3#RRVkA~!rP4-q!}c)dCXG`878E>08y$n6f4SU6Xl8dWi z=!A@h`}fc=X|jPFe4r=1NUu9PCqzsu6@ca^MQE#_(KUGVQ`S6@JC-LHTYtBh4y`l3iCc(#rwAS*TiZ2&&HsSM)UWOBWFmNMzyO~y^n;Ao*6;V#H7nQfC229&fW2?a1o=TRMjz>fJ0{99TL)fjiks}j%9)9&m^q?-#KK_#Z zsNa}gJSkwuv}MR_1xj%VbU#?37A*Ix_xFF)acM#WCtZx(A<)Z(=x=I*?Bc@Iq8ya~ z^j3ii++=i8k}RQP?qL=i8y-y23QCNYq$vlN6eV(kZF~Zjs@%~6ZhBp@i6q%NdMpE- zNCD-XSQUpvO0&*>Sg+5okG-65AdyqU|9oDCJu!$%uestzM45A4P9?*(Ljs6O`*rZCicmVu@P1=26|0srxj5oJAj&<~FcN<8>%QCg#C>7wgHoe#tGl92{NL z7cLjil-bbb|JwipmuYvNNB|~lC+qy^#;lK9;D0Muy2BdF?3~gRt%b1oEmcYR<9;b8 zHME>X%$I!_^$03To3j@#Donx##Lw&HBBHK@+S36a&2oB`QhM-~BdKKB{;=yTT`#E?1CXZsWsnLI-yH{&Q{ru|fNSeFFa*fqxCaQo#OI@%a2R z{tpBEduIQ*PvAEsuy26hu&Mhc{W^ht1N=IxedTXRVBY}0VN>@@`gH>P2KaSW`^w*t zz`g-~!=~<+^y>un4e;x%_LaXOfqet~hE3fs>DLMD8{pSj?JIvn0{aH|4V(IZS(4m= I|KIz60lQrd+5i9m diff --git a/src/static/z.wav b/src/static/z.wav deleted file mode 100644 index 6fdd51c7faabb4d8b9ea8ccd647e85dc3a63f577..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7354 zcmWmJceD)G1HkdyXGSkU^cF;k9t1)3PV_{N61_!_9zBQ>y%SxKNAw_`=q*SPPk2g{ zJVN5l%$}M)m6_!<#iIx#HZO$sIknZ=awt8gA37kn9P(9^>iApoO;Q9&6v zJN!Bvu7(F+1c%7H@S89t9uf==KJpiai<}yM|Db>HI$jzs4fm1HgU^GpYGt@GECqW6 zJpusMhHJyEx@*ui_zG_fH-^PT$Dm_?y)EIEaBJ8;Xdko-ev5X5JHs2ab@!R3;a1kjI6bTloyW!pN9au0Z=qi%KjJIeo{!nl2NJXx_{lj<~NGVL}jDN^ooDkUm+_*6{GU#f`8tBVk$>fq9^8z zf7&mHszueKwKCB^>5ri`qgv4?@p1o{|C3)QsvFgd=CH&5A%CuD7&VIO;{E=Q{&n3n zYUU~u{2%=6ux0ddbX@K7zxUgbHc{JX65sA`^A~v?qEDO!-X?#OKaF>eI!7Oq_5OPQ zlfp_lv1{SR>8sBg4EEcO@sgW14nU^FON;4kp!`(MRFqhV18 zI@h1$ACV)Xkx?Nu%b)4LGGn5#(JM2}pXwJxZD1X109eo{@#KZkB{6~6T^o^?+;t%#Sz=hGG=%yOr_xIl?OQNMw0`KF0 z?tkj7h*mo7y&irK{{UYbt&Pf(u6|eluG$!FjMBo6en(faCE5}_*X{lGegV8A+7Vq8 zt^L;ihirGWJK7Vq@LTxJ{h#8!(Y~k*ZQ?ifljMQuV3Zj(@ay}rIT9U>VpGSj?Po&A zqZ3iGtm)VAi_*mCRCF<}=2!JU@XthNqjOPlR>^=y8N$ zPCuuscosd2q|WAN^F90`dJ(0H%zkD+9eW+Uj{c3(`|163ei)}lVZ>+JCE2s@1B=S6pjnWFYz7kj+apv zi;Kkq-1KgG0F;bN#%axU@4ELAm5Iy5`Q#PviuVVt5LbvR#uvN`-g&PquN+s2lgJtG zw3km+i>t@4V4`=@^KH$zR_xp3-ZAeVSSPL<7gk5S!`=ArE__+PNtTkI+Z#slL#W`VcB`yCC9hsF)$TyL(o zjgE*%#3SQb-YjpX*N=~h$HsffG;gX`Q;m-&#P{K3Z<3eUPL8LJqR z)fjKIx1G$2XUAjs2yeLeg*P{z7k?9fONV%ay^eBWyeK}426+9wqGn0F)K&EHKKEXL z74gcrn(pcK@P5E+;p5=b*LM z+Ewh1cgLkn3$KOu6WSZ^jfcu6UK4K=JrEy=55^6=23~#dJANcS8qX$myxLwjbv!;1 zUx78f8eUGD7@vxB+G<`^?=n0SpN)H|%3dXJGPw|6jQ8>iUU{#acO||W{~Gt8rM>sO zsq#krTf7IA@QQnt%&qvgt0?Lf@g9Ms_-@=<7xD^v^YQ&SIo>And3n7L*rWKdQ<>%T za(cVOv-ny3HO}T`^FGlp;urA)klD-ZDqhF0;}1=GFTM92N{v(F6*BMwuRi55k3~#9 z>JjfQ*RhGa5$FMLvVt7(<4`lj3R=n;FKD^@5FCR6Ps69HRQ85-AnADq{(`?|uh>5< zGta`a@^UnV{mpjC>^uiwik`A3tbxhJb8`S5v4<=P~WcNi$UXu62*V%P8Oqbzh_-$~7U10!J;1zf?bAer8U!%&rGEbCe*ctW~ zt;VbI>O7GpvXd-_sL5;b%H%jZ#x|%rye{7bkFdk6xNX22^5XUY+t0p-O?XqjMeSt? ztPE+vTk>LJH`~R&XRUb~-j)Npoo!<`We5HVpMW;AO{~4?#5=o+4QxHT0lM+-e41Xv zR1=H^K|p0ybL@|-&RPvIHJcs7nDs%d;WUjxUm(X70k#b@*K zb_5&FR>Qe`9zUywvLTF;1$-gzE(WpztUp`Km++xUXF#psD|s)}ll5SI%o@Jd zRdi!r*+sB{Z{%xqC)Sa@hd1*ryoT(++Os)yJKy2VqODnLR!8pUyZO7g1#7`J>b-m~ zKL?tyChQzIzz^_2rU7ff3gaXE2+ywSusUokJ`H z_*p&|R%Vsl7+l~Nc~x71m1nKc6@HaJQ)O6bwt-ydH~0!sl9gb^*=li%-{z}HQC5V# zR7w0UZ-xr7g6u(f z^_sut9!}5Fvk4}Zr}CdczykI&;BK2}D5DHv%{8y7AcL$Hg#rpBG}TnmsgepNj$lq> zdP)Z(jTjG8=^F|_dXYiYwy)_c`T@!!vWPS~g{IIUB)iBiZiuJ!DSbkJ7r8`k(Vsk` z4{1i7PvjRB(S3T4*0Y5~VF5rAy+cRBqN13%qHocgbTcj?N{aRJ2E9(N(bA%fC@Zql zEA%q$rYeYv;xBZ8o~QFnWl=>O1ZU`JdJt3-)x|d^k)EWN-d0 zVdqELP&5<^@qW6WCh4Z4sTcqgXo9O~DO!rgb{E}63!*lnjVP(N)9th-=^#3Y401Ew zOgGU?vXkg6s*(+KJuR!diS8mdT0>XUX11s3Z2uMiD;_( z&^|OhSs_-4hO#H^Nqf-7a*bFkeA10}r621JVxvH)6YWUb+Rb8%tLQ-6)3$KC*dd^4 zLtE3=paO2GWE!rU~kRI4HhD4QPG3+Z+)`#a2*<)}~v*adATI zF*Ruox)vphQ{srKMyt|A|=yy<95 z&=T|?cuU+819eealqTUMkt8O|LbMPq=;q^nkt}ZFd^9f|rXPvN;yKJkbJ8yMsd(lp zveRs|9!wE0L{5{1W~L?ZEAd*quQJf|G#z~-Qbj2GkbwI1j^aXyuMnk#o-kS%u?|2A zsC$%1{%kZ+WCEg+$w!Kln0!J4nZ`*aZ=A*|gUlea<5%PrDQ2?BEV3F*At}V2fy^#@ z*r((v`5oqxx#T?kh&&?OaXy((=9dLzI((1(NoteA@*U@#`GfpHZjS#irEDobmi_E5@;%u}YMHjO zowJQ>by}lO<)^Zv{1$viHj)h_x9%#t$(d>`S>qIgJ!MbXOCE+R$a1obNZD8RlRxUk zA6dCDkRdeJVSw#;c!^luF56qVf$<6XpcWpb6QfQmp?#u>l zNE_0cG}F7}Zh1ZBT}O8zxxGh6IG5SaK=kBtXgkw+Y%vBdr1i5Q{B9 z3M--}K#7GjUHJ|*Ar5gW1|XeEuQI4n=rw+YhvCdBi$iS+PQia;X0xjt>TT5@Kf!)N;{fmgKfuX2lPRDIs@3XGd>1F-VX%lQ>V)7HzJ+h%{JMlHsaEP6_&UCZ$AU7d ztn&n3#+UIWTv1h2@2hXkd3+9^#WU>(s;YAXox-Q^HB>{@P&L&|djcQF$MAAfN7Z$X z;KNQ5Y^WNlMrtJ3kAKAb@E+YvHCNU24|tE00$Qn7sa!}IW5+y)L;Bh*Os0L;QOosN2}8mlhpsdy^>3J(Dj)I>E&oq!YZ1m`O?)k!d8 z@mM?tFSIk&EHzs#LnH8TycEq<^PGit2p)n5;{#@)TBN>J18{%b5B~_4s%6dq&>Q#0 zy>PN#;mWxSgxrp>{fNp;ovReuDO> zJ?aPbo^6hs;ikB>{ZZ|A?xTjdAx?)5tHbJutF4Rc;M%yWIj&BqcXdr%!>J5UsZ;6~ zbs1E}AK)r@i9V;!E34nf6`kJTvbwCUsAaG$E`v+sYwEhXp{|;exP-IP-cq;JZPghS z#YJ#Ol%(#eKh-K*5EpQMGY`}QH>!DX9-JG`g@36h>Z$q+hH!Os_!P z{T#jn1D(ckcYn|u^dFjGGU$wYkbZ^!K`&8Gm{q^!90t$PbMy>d({JmXx~%yNJw}gE zCy-a?bB4hC=svoK3h6?+uzqQh&>i##+GLCAcb$Uhcc%aI=x^eT}fBg9l%+12AxLrOf_9yztD;3q_YRq(zWzQ+Jnc?Pv|IGrR(YXdZRgn z4mtod){S)&{R7;G_M%Rxxo)9b>Na*a+U2yhZFC#mR<}jl(KfUVcF>>bPhIUM^qsTY zbkSY(UcC;jLu-))pXnaDr``-!q7_bh(?|EwpP40S30jO=fdP7;8<|FM0h;d&)x(^$ zb`F|@zDB$4NIgoA)_=hnXgYcXztrQLJ$4G3f+nL(c9Nc~r|1c2JQ{~;z-fBA(*le} zqtPfd(#+Oh>*8iO`T`9@tH3vUzVi$WLW9sil&rtii}eN55A{WTT>}h>kpV8Z4 z6;#=c>Un)ZU(|E-3(?!Z=qk|3;og=XEUKpC?gtg z|JDELH~KtGi_)O_Fw(ID07DE>WQ@{U*Dwe{1kecp|3CfBM4+I85>7SDc;*)q!w813 z21sktIUM{8|Ant%CX>lzHVy1c_yVTDM4QcIcLu|!&On&U%I3qx5Q`(d1BGG3UE1G2Ft^~rk``!eha^ai(o%H$P6|^%zXF_oCnWYrzRZWJOoS360_9R_JN;$FRWHy_3?I*B^6JM6x#wecW&B!W}o@d#Go;3 z1VeDp95RQ^En5%Pb!OOO=9oEdYQb8tCR__nnnZKT6a&>@Rp&!{)|@ptY$aF;z7Ly$ zi{_HKY=(hyu&fiAYfe8~3YLN;UG4AYrnzMffnu;Igz%0@at_!+un;T=58C@C**q`; zZE&9zAKp=q_8n;=q&H`wG0m*I=M4Y2QI7fhQeH++h8-i5u25hqFZ3gExc;$=& zS!@=Y)#e2$;BW9846-@w+qRW`0{(J70C{X4o7c7h4?r@w531XOwvb(5?}8-9-QluD zZ819o+yXbjQBcB`w599?dmUVJF50qAIlB*B2A9AjP|?0`D_H=}fwRtPTh(b}Pk~b) z5i|ldY)xCsmI24XF=v>q>wIkwgTvqu$N?JKMz*o-2z~_noMyJUbIk4md%$k+w>#U` z?nslt4zL|e1nq4H=Wn|iYzCV^qU~fm+b(tkSP#~LmY}=+%*hH?IV-_B+uMF_=h#yj!C(;BWf$3R?N7Ep z=;x#d%j`0@Zw1gB^a4G>D!baQu}QW&=;ox_4bDbe4|D<@L0z!fZn0Z!s%;P2ImvdX z^Sx~aT7i$jyI_y~!6w)MGy_eYU+sS9oNWjif(9TnIBbvDqc$g~18O^G>agb$i1BpoCK#q}W^b zw*Au$&Tm|7m?tz{wAu*$4Kaed+3RgIoZEC-$k67G!s_x!0!H7na*B?))+V kYhT-coirewlXbEcK=AaFA=x>4+H7$IsgCw From 1a2598f5a74047937e9eb1a2eab09e94c88536b5 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 29 Jul 2016 21:50:25 +0200 Subject: [PATCH 154/202] Fixed calcs. --- src/admin/pair.ts | 6 +++--- src/admin/trades.ts | 9 ++++----- src/common/models.ts | 1 + src/service/main.ts | 2 +- src/service/quoting-parameters.ts | 6 +++--- src/static/index.html | 5 +++++ 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/admin/pair.ts b/src/admin/pair.ts index 156fd3bd4..89880871c 100644 --- a/src/admin/pair.ts +++ b/src/admin/pair.ts @@ -21,11 +21,11 @@ class FormViewModel { private _submitConverter: (disp: T) => T = null) { if (this._submitConverter === null) this._submitConverter = d => d; - + _sub.registerConnectHandler(() => this.connected = true) .registerDisconnectedHandler(() => this.connected = false) .registerSubscriber(this.update, us => us.forEach(this.update)); - + this.connected = _sub.connected; this.master = angular.copy(defaultParameter); this.display = angular.copy(defaultParameter); @@ -68,7 +68,7 @@ class DisplayQuotingParameters extends FormViewModel { constructor(sub: Messaging.ISubscribe, fire: Messaging.IFire) { - super(new Models.QuotingParameters(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null), sub, fire); + super(new Models.QuotingParameters(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null), sub, fire); this.availableQuotingModes = DisplayQuotingParameters.getMapping(Models.QuotingMode); this.availableFvModels = DisplayQuotingParameters.getMapping(Models.FairValueModel); diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 6722ed8f6..6d5a87d11 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -81,7 +81,6 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri }; var addTrade = t => { - //if (this._qlParamRepo.latest.mode === Models.QuotingMode.Boomerang) if (t.alloc<0) { for(var i = 0;i<$scope.trade_statuses.length;i++) { if ($scope.trade_statuses[i].tradeId==t.tradeId) { @@ -101,8 +100,8 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri $scope.trade_statuses[i].allocprice = t.allocprice; if ($scope.trade_statuses[i].alloc >= $scope.trade_statuses[i].quantity) $scope.trade_statuses[i].side = 'K'; - if ($scope.sound) { - var audio = new Audio('/erang.mp3'); + if ($scope.sound && $('input[ng-model="pair.quotingParameters.display.audio"]').checked) { + var audio = new Audio('/audio/erang.mp3'); audio.volume = 0.5; audio.play(); } @@ -111,8 +110,8 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri } if (!exists) { $scope.trade_statuses.push(new DisplayTrade($scope, t)); - if ($scope.sound) { - var audio = new Audio('/boom.mp3'); + if ($scope.sound && $('input[ng-model="pair.quotingParameters.display.audio"]').checked) { + var audio = new Audio('/audio/boom.mp3'); audio.volume = 0.5; audio.play(); } diff --git a/src/common/models.ts b/src/common/models.ts index 33e468f43..6953a6c68 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -350,6 +350,7 @@ export class QuotingParameters { public aggressivePositionRebalancing: boolean, public tradesPerMinute: number, public tradeRateSeconds: number, + public audio: number, public longEwma: number, public shortEwma: number, public quotingEwma: number, diff --git a/src/service/main.ts b/src/service/main.ts index eac8f6737..58b4de09d 100644 --- a/src/service/main.ts +++ b/src/service/main.ts @@ -114,7 +114,7 @@ function ParseCurrencyPair(raw: string) : Models.CurrencyPair { var pair = ParseCurrencyPair(config.GetString("TradedPair")); var defaultActive : Models.SerializedQuotesActive = new Models.SerializedQuotesActive(false, moment.unix(1)); -var defaultQuotingParameters : Models.QuotingParameters = new Models.QuotingParameters(2, 0.01, Models.QuotingMode.Boomerang, Models.FairValueModel.BBO, 1, 0.9, true, Models.AutoPositionMode.EwmaBasic, false, 0.9, 569, .095, 2*.095, .095, 3, .1); +var defaultQuotingParameters : Models.QuotingParameters = new Models.QuotingParameters(2, 0.01, Models.QuotingMode.Boomerang, Models.FairValueModel.BBO, 1, 0.9, true, Models.AutoPositionMode.EwmaBasic, false, 0.9, 569, false, .095, 2*.095, .095, 3, .1); var backTestSimulationSetup = (inputData : Array, parameters : Backtest.BacktestParameters) => { var timeProvider : Utils.ITimeProvider = new Backtest.BacktestTimeProvider(_.first(inputData).time, _.last(inputData).time); diff --git a/src/service/quoting-parameters.ts b/src/service/quoting-parameters.ts index 95721c922..2ac47ba5e 100644 --- a/src/service/quoting-parameters.ts +++ b/src/service/quoting-parameters.ts @@ -22,8 +22,8 @@ class Repository implements Interfaces.IRepository { defaultParameter: T, private _rec: Messaging.IReceive, private _pub: Messaging.IPublish) { - - this._log.info("Starting parameter:", defaultParameter); + + //this._log.info("Starting parameter:", defaultParameter); _pub.registerSnapshot(() => [this.latest]); _rec.registerReceiver(this.updateParameters); this._latest = defaultParameter; @@ -37,7 +37,7 @@ class Repository implements Interfaces.IRepository { public updateParameters = (newParams: T) => { if (this._validator(newParams) && this._paramsEqual(newParams, this._latest)) { this._latest = newParams; - this._log.info("Changed parameters", this.latest); + //this._log.info("Changed parameters", this.latest); this.NewParameters.trigger(); } diff --git a/src/static/index.html b/src/static/index.html index 4654e3804..d6eb4bbea 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -196,6 +196,7 @@

    {{ exch_name }}

    apr? trds /sec + audio Applied @@ -270,6 +271,10 @@

    {{ exch_name }}

    onClick="this.select()" ng-model="pair.quotingParameters.display.tradeRateSeconds"> + + + Date: Fri, 29 Jul 2016 21:52:07 +0200 Subject: [PATCH 155/202] Fixed calcs. --- src/common/models.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/models.ts b/src/common/models.ts index 6953a6c68..34aa175e1 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -350,7 +350,7 @@ export class QuotingParameters { public aggressivePositionRebalancing: boolean, public tradesPerMinute: number, public tradeRateSeconds: number, - public audio: number, + public audio: boolean, public longEwma: number, public shortEwma: number, public quotingEwma: number, From f43d358ccf7e7d0d3072549ace0fbe1f6aeaa776 Mon Sep 17 00:00:00 2001 From: ctubio Date: Fri, 29 Jul 2016 21:55:33 +0200 Subject: [PATCH 156/202] Fixed calcs. --- src/admin/trades.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 6d5a87d11..14da493a6 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -100,7 +100,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri $scope.trade_statuses[i].allocprice = t.allocprice; if ($scope.trade_statuses[i].alloc >= $scope.trade_statuses[i].quantity) $scope.trade_statuses[i].side = 'K'; - if ($scope.sound && $('input[ng-model="pair.quotingParameters.display.audio"]').checked) { + if ($scope.sound && $('input[ng-model="pair.quotingParameters.display.audio"]:checked')) { var audio = new Audio('/audio/erang.mp3'); audio.volume = 0.5; audio.play(); @@ -110,7 +110,7 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri } if (!exists) { $scope.trade_statuses.push(new DisplayTrade($scope, t)); - if ($scope.sound && $('input[ng-model="pair.quotingParameters.display.audio"]').checked) { + if ($scope.sound && $('input[ng-model="pair.quotingParameters.display.audio"]:checked')) { var audio = new Audio('/audio/boom.mp3'); audio.volume = 0.5; audio.play(); From 8098c1837e718a875a04499e61c51eb493263ed7 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 30 Jul 2016 16:52:33 +0200 Subject: [PATCH 157/202] Fixed calcs. --- src/service/persister.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/persister.ts b/src/service/persister.ts index 5a3c7034d..07b877b85 100644 --- a/src/service/persister.ts +++ b/src/service/persister.ts @@ -168,7 +168,7 @@ export class Persister implements ILoadAll { public persist = (report: T) => { this.collection.then(coll => { this._saver(report); - if (this._dbName=="fv" || this._dbName=="md" || this._dbName=="tsv") + if (["fv","md","msg","mt","pos","tbd","osr","tsv"].indexOf(this._dbName)>-1) coll.deleteMany({ time: { $exists:true } }, err => { if (err) this._log.error(err, "Unable to deleteMany", this._dbName, report); From 724f26187349a82f6d2730f03175412adf5732c1 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 30 Jul 2016 16:58:49 +0200 Subject: [PATCH 158/202] Fixed calcs. --- src/common/messaging.ts | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/common/messaging.ts b/src/common/messaging.ts index 082ed1378..b3a9cbdce 100644 --- a/src/common/messaging.ts +++ b/src/common/messaging.ts @@ -23,16 +23,16 @@ export class Publisher implements IPublish { this.registerSnapshot(snapshot || null); var onConnection = s => { - this._log("socket", s.id, "connected for Publisher", topic); + // this._log("socket", s.id, "connected for Publisher", topic); - s.on("disconnect", () => { - this._log("socket", s.id, "disconnected for Publisher", topic); - }); + // s.on("disconnect", () => { + // this._log("socket", s.id, "disconnected for Publisher", topic); + // }); s.on(Prefixes.SUBSCRIBE + "-" + topic, () => { if (this._snapshot !== null) { var snapshot = this._snapshot(); - this._log("socket", s.id, "asking for snapshot on topic", topic); + // this._log("socket", s.id, "asking for snapshot on topic", topic); s.emit(Prefixes.SNAPSHOT + "-" + topic, snapshot); } }); @@ -84,7 +84,7 @@ export class Subscriber implements ISubscribe { private _log : (...args: any[]) => void) { this._socket = io; - this._log("creating subscriber to", this.topic, "; connected?", this.connected); + // this._log("creating subscriber to", this.topic, "; connected?", this.connected); if (this.connected) this.onConnect(); @@ -100,7 +100,7 @@ export class Subscriber implements ISubscribe { } private onConnect = () => { - this._log("connect to", this.topic); + // this._log("connect to", this.topic); if (this._connectHandler !== null) { this._connectHandler(); } @@ -109,7 +109,7 @@ export class Subscriber implements ISubscribe { }; private onDisconnect = () => { - this._log("disconnected from", this.topic); + // this._log("disconnected from", this.topic); if (this._disconnectHandler !== null) this._disconnectHandler(); }; @@ -120,13 +120,13 @@ export class Subscriber implements ISubscribe { }; private onSnapshot = (msgs : T[]) => { - this._log("handling snapshot for", this.topic, "nMsgs:", msgs.length); + // this._log("handling snapshot for", this.topic, "nMsgs:", msgs.length); if (this._snapshotHandler !== null) this._snapshotHandler(msgs); }; public disconnect = () => { - this._log("forcing disconnection from ", this.topic); + // this._log("forcing disconnection from ", this.topic); this._socket.off("connect", this.onConnect); this._socket.off("disconnect", this.onDisconnect); this._socket.off(Prefixes.MESSAGE + "-" + this.topic, this.onIncremental); @@ -183,8 +183,8 @@ export class Fire implements IFire { constructor(private topic : string, io : SocketIOClient.Socket, _log : (...args: any[]) => void) { this._socket = io; - this._socket.on("connect", () => _log("Fire connected to", this.topic)) - .on("disconnect", () => _log("Fire disconnected to", this.topic)); + // this._socket.on("connect", () => _log("Fire connected to", this.topic)) + // .on("disconnect", () => _log("Fire disconnected to", this.topic)); } public fire = (msg : T) : void => { @@ -205,14 +205,14 @@ export class Receiver implements IReceive { constructor(private topic : string, io : SocketIO.Server, private _log : (...args: any[]) => void) { var onConnection = (s : SocketIO.Socket) => { - this._log("socket", s.id, "connected for Receiver", topic); + // this._log("socket", s.id, "connected for Receiver", topic); s.on(Prefixes.MESSAGE + "-" + this.topic, msg => { if (this._handler !== null) this._handler(msg); }); - s.on("error", e => { - _log("error in Receiver", e.stack, e.message); - }); + // s.on("error", e => { + // _log("error in Receiver", e.stack, e.message); + // }); }; io.on("connection", onConnection); From dd10cc57f665edd7c3ac48709c31841dda669690 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 30 Jul 2016 17:34:10 +0200 Subject: [PATCH 159/202] Fixed calcs. --- src/admin/pair.ts | 2 +- src/common/models.ts | 3 ++- src/service/main.ts | 2 +- src/service/quoting-engine.ts | 6 ++--- src/service/quoting-parameters.ts | 2 +- src/service/quoting-styles/mid-market.ts | 11 +++++---- src/service/quoting-styles/top-join.ts | 16 ++++++------- src/service/safety.ts | 30 +++++++++++++----------- src/static/index.html | 11 +++++++-- 9 files changed, 47 insertions(+), 36 deletions(-) diff --git a/src/admin/pair.ts b/src/admin/pair.ts index 89880871c..6dec4f90f 100644 --- a/src/admin/pair.ts +++ b/src/admin/pair.ts @@ -68,7 +68,7 @@ class DisplayQuotingParameters extends FormViewModel { constructor(sub: Messaging.ISubscribe, fire: Messaging.IFire) { - super(new Models.QuotingParameters(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null), sub, fire); + super(new Models.QuotingParameters(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null), sub, fire); this.availableQuotingModes = DisplayQuotingParameters.getMapping(Models.QuotingMode); this.availableFvModels = DisplayQuotingParameters.getMapping(Models.FairValueModel); diff --git a/src/common/models.ts b/src/common/models.ts index 34aa175e1..ce23fbf5b 100644 --- a/src/common/models.ts +++ b/src/common/models.ts @@ -340,7 +340,8 @@ export enum AutoPositionMode { Off, EwmaBasic } export class QuotingParameters { constructor(public width: number, - public size: number, + public buySize: number, + public sellSize: number, public mode: QuotingMode, public fvModel: FairValueModel, public targetBasePosition: number, diff --git a/src/service/main.ts b/src/service/main.ts index 58b4de09d..7dbd968fc 100644 --- a/src/service/main.ts +++ b/src/service/main.ts @@ -114,7 +114,7 @@ function ParseCurrencyPair(raw: string) : Models.CurrencyPair { var pair = ParseCurrencyPair(config.GetString("TradedPair")); var defaultActive : Models.SerializedQuotesActive = new Models.SerializedQuotesActive(false, moment.unix(1)); -var defaultQuotingParameters : Models.QuotingParameters = new Models.QuotingParameters(2, 0.01, Models.QuotingMode.Boomerang, Models.FairValueModel.BBO, 1, 0.9, true, Models.AutoPositionMode.EwmaBasic, false, 0.9, 569, false, .095, 2*.095, .095, 3, .1); +var defaultQuotingParameters : Models.QuotingParameters = new Models.QuotingParameters(2, 0.02, 0.01, Models.QuotingMode.Boomerang, Models.FairValueModel.BBO, 1, 0.9, true, Models.AutoPositionMode.EwmaBasic, false, 0.9, 569, false, .095, 2*.095, .095, 3, .1); var backTestSimulationSetup = (inputData : Array, parameters : Backtest.BacktestParameters) => { var timeProvider : Utils.ITimeProvider = new Backtest.BacktestTimeProvider(_.first(inputData).time, _.last(inputData).time); diff --git a/src/service/quoting-engine.ts b/src/service/quoting-engine.ts index a3f9f5211..91c124452 100644 --- a/src/service/quoting-engine.ts +++ b/src/service/quoting-engine.ts @@ -97,19 +97,19 @@ export class QuotingEngine { var latestPosition = this._positionBroker.latestReport; var totalBasePosition = latestPosition.baseAmount + latestPosition.baseHeldAmount; - unrounded.bidSz *= 2; + if (totalBasePosition < targetBasePosition - params.positionDivergence) { unrounded.askPx = null; unrounded.askSz = null; if (params.aggressivePositionRebalancing) - unrounded.bidSz = Math.min(params.aprMultiplier*params.size, targetBasePosition - totalBasePosition); + unrounded.bidSz = Math.min(params.aprMultiplier*params.buySize, targetBasePosition - totalBasePosition); } if (totalBasePosition > targetBasePosition + params.positionDivergence) { unrounded.bidPx = null; unrounded.bidSz = null; if (params.aggressivePositionRebalancing) - unrounded.askSz = Math.min(params.aprMultiplier*params.size, totalBasePosition - targetBasePosition); + unrounded.askSz = Math.min(params.aprMultiplier*params.sellSize, totalBasePosition - targetBasePosition); } var safety = this._safeties.latest; diff --git a/src/service/quoting-parameters.ts b/src/service/quoting-parameters.ts index 2ac47ba5e..55f6dc52a 100644 --- a/src/service/quoting-parameters.ts +++ b/src/service/quoting-parameters.ts @@ -50,7 +50,7 @@ export class QuotingParametersRepository extends Repository, initParam: Models.QuotingParameters) { super("qpr", - (p: Models.QuotingParameters) => p.size > 0 || p.width > 0, + (p: Models.QuotingParameters) => p.buySize > 0 || p.sellSize > 0 || p.width > 0, (a: Models.QuotingParameters, b: Models.QuotingParameters) => !_.isEqual(a, b), initParam, rec, pub); diff --git a/src/service/quoting-styles/mid-market.ts b/src/service/quoting-styles/mid-market.ts index a9905a341..06d6b66cf 100644 --- a/src/service/quoting-styles/mid-market.ts +++ b/src/service/quoting-styles/mid-market.ts @@ -5,14 +5,15 @@ import Models = require("../../common/models"); export class MidMarketQuoteStyle implements StyleHelpers.QuoteStyle { Mode = Models.QuotingMode.Mid; - + GenerateQuote = (market: Models.Market, fv: Models.FairValue, params: Models.QuotingParameters) : StyleHelpers.GeneratedQuote => { var width = params.width; - var size = params.size; - + var buySize = params.buySize; + var sellSize = params.sellSize; + var bidPx = Math.max(fv.price - width, 0); var askPx = fv.price + width; - - return new StyleHelpers.GeneratedQuote(bidPx, size, askPx, size); + + return new StyleHelpers.GeneratedQuote(bidPx, buySize, askPx, sellSize); }; } \ No newline at end of file diff --git a/src/service/quoting-styles/top-join.ts b/src/service/quoting-styles/top-join.ts index ac158ba1b..0135984fa 100644 --- a/src/service/quoting-styles/top-join.ts +++ b/src/service/quoting-styles/top-join.ts @@ -80,8 +80,8 @@ function computeTopJoinQuote(filteredMkt: Models.Market, fv: Models.FairValue, p var minAsk = fv.price + params.width / 2.0; genQt.askPx = Math.max(minAsk, genQt.askPx); - genQt.bidSz = params.size; - genQt.askSz = params.size; + genQt.bidSz = params.buySize; + genQt.askSz = params.sellSize; return genQt; } @@ -105,8 +105,8 @@ function computeInverseJoinQuote(filteredMkt: Models.Market, fv: Models.FairValu genQt.bidPx -= params.width / 4.0; } - genQt.bidSz = params.size; - genQt.askSz = params.size; + genQt.bidSz = params.buySize; + genQt.askSz = params.sellSize; return genQt; } @@ -129,8 +129,8 @@ function computePingPongQuote(filteredMkt: Models.Market, fv: Models.FairValue, var minAsk = fv.price + params.width / 8.0; genQt.askPx = Math.max(minAsk, genQt.askPx); - genQt.bidSz = params.size; - genQt.askSz = params.size; + genQt.bidSz = params.buySize; + genQt.askSz = params.sellSize; return genQt; } @@ -153,8 +153,8 @@ function computeBoomerangQuote(filteredMkt: Models.Market, fv: Models.FairValue, var minAsk = fv.price + params.width / 8.0; genQt.askPx = Math.max(minAsk, genQt.askPx); - genQt.bidSz = params.size; - genQt.askSz = params.size; + genQt.bidSz = params.buySize; + genQt.askSz = params.sellSize; return genQt; } \ No newline at end of file diff --git a/src/service/safety.ts b/src/service/safety.ts index 9acf80315..d1de0843b 100644 --- a/src/service/safety.ts +++ b/src/service/safety.ts @@ -89,39 +89,39 @@ export class SafetyCalculator { if (fv != null) {fvp = fv.price;} trades.sort(function(a,b){return a.price>b.price?1:(a.pricetrades[ti].price && fvp-settings.widthtrades[ti].price && fvp-settings.width=settings.size) break; + if (buyPq>=settings.sellSize) break; } trades.sort(function(a,b){return a.priceb.price?-1:0);}); if (!buyPq) for (var ti = 0;titrades[ti].price) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].alloctrades[ti].price) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].alloc=settings.size) break; + if (buyPq>=settings.sellSize) break; } trades.sort(function(a,b){return a.priceb.price?-1:0);}); for (var ti = 0;titrades[ti].price)) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].alloctrades[ti].price)) && (settings.mode !== Models.QuotingMode.Boomerang || trades[ti].alloc=settings.size*2) break; + if (sellPq>=settings.buySize) break; } trades.sort(function(a,b){return a.price>b.price?1:(a.price=settings.size*2) break; + if (sellPq>=settings.buySize) break; } if (buyPq) buyPing /= buyPq; @@ -157,9 +157,11 @@ export class SafetyCalculator { } } - var computeSafety = (t: Models.Trade[]) => t.reduce((sum, t) => sum + t.quantity, 0) / this._qlParams.latest.size; + var computeSafety = (t: Models.Trade[]) => t.reduce((sum, t) => sum + t.quantity, 0) / (this._qlParams.latest.buySize + this._qlParams.latest.sellSize / 2); + var computeSafetyBuy = (t: Models.Trade[]) => t.reduce((sum, t) => sum + t.quantity, 0) / this._qlParams.latest.buySize; + var computeSafetySell = (t: Models.Trade[]) => t.reduce((sum, t) => sum + t.quantity, 0) / this._qlParams.latest.sellSize; - this.latest = new Models.TradeSafety(computeSafety(this._buys), computeSafety(this._sells), + this.latest = new Models.TradeSafety(computeSafetyBuy(this._buys), computeSafetySell(this._sells), computeSafety(this._buys.concat(this._sells)), buyPing, sellPong, this._timeProvider.utcNow()); }; diff --git a/src/static/index.html b/src/static/index.html index d6eb4bbea..16ae6f200 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -189,7 +189,8 @@

    {{ exch_name }}

    fv apMode width - size + buySize + sellSize tbp pDiv ewma? @@ -237,7 +238,13 @@

    {{ exch_name }}

    + ng-model="pair.quotingParameters.display.buySize"> + + + Date: Sat, 30 Jul 2016 17:36:13 +0200 Subject: [PATCH 160/202] Fixed calcs. --- src/static/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/static/index.html b/src/static/index.html index 16ae6f200..d369e1df9 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -189,8 +189,8 @@

    {{ exch_name }}

    fv apMode width - buySize - sellSize + bidSz + askSz tbp pDiv ewma? From dc8abcf70afaaccd6441542797a6691087ba2581 Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 30 Jul 2016 18:02:00 +0200 Subject: [PATCH 161/202] Fixed calcs. --- src/static/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/index.html b/src/static/index.html index d369e1df9..e431ea40e 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -213,7 +213,7 @@

    {{ exch_name }}

    - + From 9ecfc6e961f92f51ff08ba7b438c6be6e04c280c Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 30 Jul 2016 18:03:09 +0200 Subject: [PATCH 162/202] Fixed calcs. --- src/static/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/index.html b/src/static/index.html index e431ea40e..6a76248a0 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -223,7 +223,7 @@

    {{ exch_name }}

    ng-model="pair.quotingParameters.display.fvModel" ng-options="x.val as x.str for x in pair.quotingParameters.availableFvModels"> - + From 9d9f3086d0b5134d4098a1af584bd6710b489b5e Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 30 Jul 2016 18:04:15 +0200 Subject: [PATCH 163/202] Fixed calcs. --- src/static/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/index.html b/src/static/index.html index 6a76248a0..f4d90da8c 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -218,7 +218,7 @@

    {{ exch_name }}

    ng-model="pair.quotingParameters.display.mode" ng-options="x.val as x.str for x in pair.quotingParameters.availableQuotingModes"> - + From 2f1a9c5e3234dfc096b8834e6ae1a9591ca07f5b Mon Sep 17 00:00:00 2001 From: ctubio Date: Sat, 30 Jul 2016 18:09:46 +0200 Subject: [PATCH 164/202] Fixed calcs. --- src/admin/trades.ts | 4 ++-- src/static/index.html | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/admin/trades.ts b/src/admin/trades.ts index 14da493a6..22279bff0 100644 --- a/src/admin/trades.ts +++ b/src/admin/trades.ts @@ -75,8 +75,8 @@ var TradesListController = ($scope : TradesScope, $log : ng.ILogService, subscri } }}, {width: 60, field:'value', displayName:'val', cellFilter: 'currency:"$":3'}, - {width: 50, field:'alloc', displayName:'alloc'}, - {width: 55, field:'allocprice', displayName:'px', cellFilter: 'currency'} + {width: 50, field:'alloc', displayName:'Kqty'}, + {width: 55, field:'allocprice', displayName:'Kpx', cellFilter: 'currency'} ] }; diff --git a/src/static/index.html b/src/static/index.html index f4d90da8c..b3a2abd5e 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -216,7 +216,8 @@

    {{ exch_name }}

    + ng-options="x.val as x.str for x in pair.quotingParameters.availableQuotingModes" + onchange="console.log(this.value);"> + ng-options="x.val as x.str for x in pair.quotingParameters.availableQuotingModes">