From fc9bd1757b698fd8471a70a665eeefd20c041452 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 2 May 2018 14:48:36 +0200 Subject: [PATCH] Taking market price from Bruce --- .vs/AACloud/v15/.suo | Bin 102400 -> 100864 bytes Assistant.js | 329 ++++++++++++++++++++++--------------------- this.config.json | 4 +- 3 files changed, 168 insertions(+), 165 deletions(-) diff --git a/.vs/AACloud/v15/.suo b/.vs/AACloud/v15/.suo index 12334df666058e1fc111aeaaf73a78ba500dcb79..8e883487b15302f051b255ea22255e161d9498f7 100644 GIT binary patch delta 4113 zcmds)4Nz3q7035Hc9&h;MNkpsLl;C{DN`-m>LT&4#a~mfl81D z62UZ31WaHGXylWoDg2S%WSxvF2bc=BF_~jqo`ENGO$b`?tAqZgAu%s}J(vT+!NcHh z$bAsD0vN#xAonN3ri10+D_{wb_*Y?9ff|qmR_k;*x_UTkz*?{lJPPW-V_-el0HlT+ zVH?2Xzy_MYOulR$XL%A{3wQ#!lsa=p`Q=uruQOC%zNM6!tmvHwxMM*wXDGvXbNK$` zMF`{rS>0UNJdg^a!9*~fGffH6^WjOxNZ8O`Bv7gBgI@N5_nYjw&%==d#egi33(Oz| zNWn5dHW&x0KqQbs9k8+;hnWl`r%Fk`gR5d7TXG)|6@3jfgBL)kyx!LGNi?gqJeHR6 zHbZS(3HoHjg+VL6G;h8IXJPk%=fGaj3ibg8Z6HR`>Dpmcupc}R z4ge3}I(wS_s5l4hc9R#*kLBXL-M;uuI6nbCa1xvXKLe-1Pr(@=)1M96bFe=L=fN*P zH@E;KXAmymv7OIPp80?BJIb`gs7Vo=Uw991jxRC?&IZv0CGH_UaQ%RnL#_CK1&y$3FES6ik*6g7%(kJ(DcxhcNnpG+Zg z7wv}T9~PJb0g3gmDl|!gh&YtMjWwla!VdKhy-n+_v5-4mafPMObWTo8V#kP?hBPd9 z7w7gAx#}$Ztak>N_2hoe&2WvjX}0NC$GDmo=+%FiskxN9luYhzzF?+(=-EG{*OG+6 ze}jNDcZm_jFb9fZ!S&!`gGI3hiV{f05yQECtGT|+s6AH6R&Ux_GReu3jPdy5)C^Z! zqw*Hr?2Hob9klt>q)xRx#Tl)v|#DU?w;SUId50H$exGgVPPZ1w23o zkrp^E4;Clh^D2S`;0VxwJeRM*{tz4ko#1sKH@yM-BhYuWdL+5`D6V>JiFC+uHn{ZO zdJDNc*mBoZ^6u^;?y8yNvOH}{LH(!69_+THwoHYS4rICv*i0}T%m6dNmq8Yo1?~ls zmkoO#m<{HD955H;gItgYB(DIr5X=Mf!2+-lECNNKnD7#~A5IA<1v>ychF{fe`?2Ix zU1Xr~@{6#Y7IEYyD2<&fw`f}qK0~g(1tyW0F;NZ|@32Lk_)HS_RKyv&5bSHM{_`Dm!oBrQs@0mlU84N2D8%aX zzB*JKhJZNucI;$MjZ5szQRo!8k4La`Yzn82P1JHuTqDia{u1%&@6L96_1@D}qr=j5 z>-g}-arjO#a+%-49o^X+_iHz&zBP(%-FB|Jyp+qjBLaPn%Qmj+HfoM{9EON1I3VP} z3Wwz0Yv;b}HqFuJ4CBlX^SJ7Rd+B99{9ZM`(h{xq&86Y|#=CZ2e?8G-AZm{whg!Xa z8ZGTqkez|Qt+|C6oj!!g-J|#HB;uOi)<&J!Q}Khp)K=W)A_lZo87M|?$Zia-JTe2kT+?dP4q>>w{XtK3)#1Rg?gois#Sj>#qi$u zO@kFu&pk+4oYT96t-S^63(F}#TE3$OTAHr|ew_O8avH1ojyXtm5=C}KuAv4}H||0` zeQU|7-oJvJoxXLbqxTGc{)kN@J4e+~8jkMJY^Ap>YELfZk1h-it()ju3}3$R3tXs3 z4pU657JK#&1}TVIzlvTw;#*Ioeo{%3*w-6J+r8aY7PeiohgIR5?dT$^wuVL!o6gCX z{eiAehSLnr^T+dlK{)JeF{p-}^w)n`I+a5;a|D{9e@iQwVP8xmhwid6<__u(A4Bld zu_f|y2m_(^xmW|zR^lI^M(m#7KT9o%rW7@P1J$WJ^c1C5Y^Jm7J6kAK)UUgeaI@m^ z3jc&D*#~ewT*@#ny&xYHI^9Z+%#Ky7tYlN25oBj2X7q>$bSXtmjYDtgylABiI<|(K z1Jb28Id{}tPZ{akq1-_YJC!e@+Uh$B)w7KBceNfz9E(W#&lSaEA;q&APwuImV>`!2 p(zP&8GZ`g%>?t~@SI_Mrd*`1TD3bW?Uj;LcHPg8WZC+0n{T+s8u-X6s delta 5391 zcmeI0eNfcL8OQJWaR+yB!XYp6W;hU&L+|kL1>-AsaNrAwpcn~a0}2?7QG~;4f^so7 zW*WwUTkvPpSbEN2lCdxHQ%O^to2{SCrH1`z2qcn)!0t| z=rSL6_u2jJKKtzM^DNj}{B3RiP17SHWHOlo+!`1dKqe!Qe4rp!P-z-e+CN|XkcwEH zkjFBOlceiH6si2t0euI;ShRdXXeMfNfE+~g7PeFwOE0hu^4MJ7D+;n0Fb4Fau16jR z#(^B51Y^NokPGTT8ZZMDNCc&T^~%GCaUD&l7{JdNDZ&inQ91|`zzmQIW`Vh2GUx;W zfUDBcToA8%8kLuU)LbxvHnW#hE7U3Ob{lfmM;nwahx~`GTS<1MCV|^2%-uU3c?L)V zq2O__kfkbP!?{WLd^~ZJaMQ3-c{nX&b@F&Qw*uRt)KLRFDjyrM2(7_j=-Ng!@OAMq z__}z`Q=z-O#houj-T@Ya`CuAY0tx_M_cMSmxeQ2v+ljCDd*CUs0Pt}~B3}-k2Nj@F zCYvc+fx@$(3akXrfmML3x*GW!unDXMHJ}z)K^<7fexrz2^PXDNUILCl!M=Tql8ZR3 zaeERgd^JgxM%XIwBs({3l){Ws21?_atJTaTIv@O#UP-GN705Ejq|y&qT}+;eFrOH6>@eXB3Vj|yAWhoYgN#8;D;FGHRu%| z$WUql5duqfgf&+OuvKckocCe7)jB0F@Wf83b?mppqEyGw_c-Wrt?E^FDkPu9jnOIj z{s_Km{o+2=9p>{<(4e{yAV~wu-=}X3e73^qND(^9PuwnJwzxzoar}koXs+f&e8+R1 zj-mVt*vg{!zo>l2-NJS^#!dP@Di&}66a&74*~kxp!{C>I57F(;dHFc*n>|>rcnh+9 z%>{qAYqXL!uU9cF&)q2t`N-yiFs5ysKEr{^>tH9?1$Kisz#i};&<1`CJV&Y>Wj+f} z6WQyH@lW25jy>+L-bLO8jstdWe^e+R)|2)@_*QelUmZ^c+w~UZXjJ(P^&B6`THi?a z_1!8`K+5mFr-k*c&sRPHL71=5x?#S8Qn}>Zb9#S%);^O-H&^&8?M>aR+b>n>Yf@83 zjo{A&ea4+!r0BqIV{sKgV|PCl%pWh_ULBEfk$7d@69t<#zSm|+O-)N3rRGWP`niH zxJdSq3}f6%hhkNhRmC6j`E@Nt@$w*Vfz_zPXoCfqZA)l{+_?Bexj zLdr`PTFb0;wb}(0)oW_3EaCdE=uO_je$o&ormHDL+!#c={HD%Dh#J#TO;X+V34r|ed?WKnHJO$r(?<5;1- zWpK)?U#GF&>!qzrDT)<+t)uOO(rf)1Cid&tr&r>{v(qSBELKno(_YrvZ?riS3I z4#q2Pq$<7BGCL=k>8cRv>CJQgpySE1jjvZM%A(Ve`&}aZ9`1Y=qb2b6Z*R_ zdV;+-5b5}w95)5WNx^>Aq$xVX0{~o7;knUcr|#5=1w@fCI9Wb-XOH)iXBkCXF6sD~ zQIhkjiQ3CaXrD*aUPXS6Qvyo}k90Yeyz}*)2Uk%pF^U)=jX3=`1zYwzQ>SS)IjQ5L zQngfizK#Cxl||$K3ebboukqJuD>w<8-L;1?fdkz zF?V-gqI0f~n`z%n@_YN4_I#4J8fbRwG};*1>~rusP|k&3uFz}0;=j){gNXTGnJBKv zq^^6$K?No6O^}_{S`obHA}Mt-YA!;#Wbm*cIcpc+I1CHlfU4i+74~ zf%>wF@srEamKhE0r6jaA(3F4}{_KToHOa}z{b-_74@vGfQEuXE-bL%3{O{d`=ruIT zWu+Q2CQqDTNKLgE4d$#=(H2Nfd(jfjlwU7;y7;ThRkp1cKb%`Q`W#!^5H1*BVMoK$ z+bc;p985MEX*L**W@F|QV|I3S=7f#))8|#yF3+x7RpEJusl59sIzz}d;UQmRcR2rH zoz6nC3A0OT@Jg&L@y_!QGd!~3sW0a{GMMyEzPJ4UV?M!C_NUmZh2ChV$swcXB^|*Z}SCGA& zLs8=9e45=kyPh_yJ5O3Ejl@fpG*xV?q$cs?deX6;y;GU#Y_J$yNj;7}(j?~8S$$X7 q8c%Wj(d-u>v-m!uqa*XztXi|Ws$%`nFGNiRUE?wRL55R#hx-=_`Mq%f diff --git a/Assistant.js b/Assistant.js index 2e8626eb4..8d4d9f35e 100644 --- a/Assistant.js +++ b/Assistant.js @@ -71,12 +71,13 @@ global.PLATFORM_CONFIG.marketRateProvider.dataSet + "-" + global.PLATFORM_CONFIG.marketRateProvider.dataSetVersion; + if (FULL_LOG === true) { logger.write("[INFO] initialize -> getMarketRate -> key = " + key); } + let dataSet = thisObject.dataDependencies.dataSets.get(key); - let timePeriod = "01-min"; let dateForPath = bot.processDatetime.getUTCFullYear() + '/' + utilities.pad(bot.processDatetime.getUTCMonth() + 1, 2) + '/' + utilities.pad(bot.processDatetime.getUTCDate(), 2); let fileName = '' + global.MARKET.assetA + '_' + global.MARKET.assetB + '.json'; - let filePath = global.PLATFORM_CONFIG.marketRateProvider.product + "/" + global.PLATFORM_CONFIG.marketRateProvider.dataSet + "/" + timePeriod + "/" + dateForPath; + let filePath = global.PLATFORM_CONFIG.marketRateProvider.product + "/" + global.PLATFORM_CONFIG.marketRateProvider.dataSet + "/" + dateForPath; dataSet.getTextFile(filePath, fileName, onFileReceived, true); @@ -458,76 +459,6 @@ getPositionTradesAtExchange(position.id, confirmOrderWasPartiallyExecuted); return; - function confirmOrderWasPartiallyExecuted(pTrades) { - - try { - if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionFound -> confirmOrderWasPartiallyExecuted -> Entering function."); } - - /* - - To confirm everything is ok, we will add all the amounts on trades plus the remaining amounts - at the order at the exchange and they must be equal to the one on file. Otherwise something very strange could - have happened, in which case we will halt the bot execution. - - */ - - let sumAssetA = 0; - let sumAssetB = 0; - - for (let k = 0; k < pTrades.length; k++) { - - sumAssetA = sumAssetA + pTrades[k].amountA; - sumAssetB = sumAssetB + pTrades[k].amountB; - - } - - /* To this we add the current position amounts. */ - - sumAssetA = sumAssetA + exchangePosition.amountA; - sumAssetB = sumAssetB + exchangePosition.amountB; - - /* And finally we add the fees */ - - sumAssetA = sumAssetA + exchangePosition.fee; - - if ( - position.amountA !== sumAssetA || - position.amountB !== sumAssetB - ) { - logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionFound > confirmOrderWasPartiallyExecuted -> Cannot be confirmed that a partially execution was done well."); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - - /* - - Confirmed that order was partially executed. Next thing to do is to remember the trades and the new position. - - */ - - position.amountA = exchangePosition.amountA; - position.amountB = exchangePosition.amountB; - position.date = (new Date(exchangePosition.date)).valueOf(); - - applyTradesToContext(pTrades); - - let newTransaction = { - type: position.type + " partially executed", - position: position - }; - - context.executionContext.transactions.push(newTransaction); - - /* All done. */ - - next(); - - } catch (err) { - logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionFound > confirmOrderWasPartiallyExecuted -> err = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - } } } @@ -539,114 +470,115 @@ getPositionTradesAtExchange(position.id, confirmOrderWasExecuted); - function getPositionTradesAtExchange(pPositionId, innerCallBack) { + } - try { + function getPositionTradesAtExchange(pPositionId, innerCallBack) { - if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Entering function."); } - if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> pPositionId = " + pPositionId); } + try { - /* - - Given one position, we request all the associated trades to it. - - */ + if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Entering function."); } + if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> pPositionId = " + pPositionId); } - switch (bot.runMode) { + /* + + Given one position, we request all the associated trades to it. + + */ - case "Live": { + switch (bot.runMode) { - if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Live Mode Detected."); } - exchangeAPI.getExecutedTrades(pPositionId, onResponse); - return; + case "Live": { - } + if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Live Mode Detected."); } + exchangeAPI.getExecutedTrades(pPositionId, onResponse); + return; - case "Backtest": { - - if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Backtest Mode Detected."); } - - let trades = []; - - /* We look for the position at the executionContext */ - - for (let i = 0; i < context.executionContext.positions.length; i++) { - - let thisPosition = context.executionContext.positions[i]; - - if (thisPosition.id === pPositionId) { - - let trade = { - id: Math.trunc(Math.random(1) * 1000000), - type: thisPosition.type, - rate: thisPosition.rate, - amountA: thisPosition.amountA, - amountB: thisPosition.amountB, - fee: 0, - date: (new Date()).valueOf() - } - - trades.push(trade); - - onResponse(global.DEFAULT_OK_RESPONSE, trades); - - return; - } - } - - logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Position not found at Executioin Context."); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - - case "Competition": { - - if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Competition Mode Detected."); } - exchangeAPI.getExecutedTrades(pPositionId, onResponse); - return; - } - - default: { - logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Unexpected bot.runMode."); - logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> bot.runMode = " + bot.runMode); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; - } } - function onResponse(err, pTrades) { + case "Backtest": { - try { - if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> onResponse -> Entering function."); } + if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Backtest Mode Detected."); } - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { // Everything went well, we have the information requested. - logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> onResponse -> Execution finished well. :-)"); - innerCallBack(pTrades); + let trades = []; + + /* We look for the position at the executionContext */ + + for (let i = 0; i < context.executionContext.positions.length; i++) { + + let thisPosition = context.executionContext.positions[i]; + + if (thisPosition.id === pPositionId) { + + let trade = { + id: Math.trunc(Math.random(1) * 1000000), + type: thisPosition.type, + rate: thisPosition.rate, + amountA: thisPosition.amountA, + amountB: thisPosition.amountB, + fee: 0, + date: (new Date()).valueOf() } - break; - case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. - logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> onResponse -> Retry Later. Requesting Execution Retry."); - callBack(global.DEFAULT_RETRY_RESPONSE); - return; - } - break; - case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. - logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> onResponse -> Operation Failed. Aborting the process."); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - break; + + trades.push(trade); + + onResponse(global.DEFAULT_OK_RESPONSE, trades); + + return; } - } catch (err) { - logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> onResponse -> err = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); } + + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Position not found at Executioin Context."); + callBack(global.DEFAULT_FAIL_RESPONSE); + return; + } + + case "Competition": { + + if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Competition Mode Detected."); } + exchangeAPI.getExecutedTrades(pPositionId, onResponse); + return; + } + + default: { + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Unexpected bot.runMode."); + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> bot.runMode = " + bot.runMode); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return; } - } catch (err) { - logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> err = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); } + + function onResponse(err, pTrades) { + + try { + if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> onResponse -> Entering function."); } + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { // Everything went well, we have the information requested. + logger.write("[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> onResponse -> Execution finished well. :-)"); + innerCallBack(pTrades); + } + break; + case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> onResponse -> Retry Later. Requesting Execution Retry."); + callBack(global.DEFAULT_RETRY_RESPONSE); + return; + } + break; + case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> onResponse -> Operation Failed. Aborting the process."); + callBack(global.DEFAULT_FAIL_RESPONSE); + return; + } + break; + } + } catch (err) { + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> onResponse -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + } catch (err) { + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); } } @@ -723,6 +655,77 @@ } } + function confirmOrderWasPartiallyExecuted(pTrades) { + + try { + if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> Entering function."); } + + /* + + To confirm everything is ok, we will add all the amounts on trades plus the remaining amounts + at the order at the exchange and they must be equal to the one on file. Otherwise something very strange could + have happened, in which case we will halt the bot execution. + + */ + + let sumAssetA = 0; + let sumAssetB = 0; + + for (let k = 0; k < pTrades.length; k++) { + + sumAssetA = sumAssetA + pTrades[k].amountA; + sumAssetB = sumAssetB + pTrades[k].amountB; + + } + + /* To this we add the current position amounts. */ + + sumAssetA = sumAssetA + exchangePosition.amountA; + sumAssetB = sumAssetB + exchangePosition.amountB; + + /* And finally we add the fees */ + + sumAssetA = sumAssetA + exchangePosition.fee; + + if ( + position.amountA !== sumAssetA || + position.amountB !== sumAssetB + ) { + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> Cannot be confirmed that a partially execution was done well."); + callBack(global.DEFAULT_FAIL_RESPONSE); + return; + } + + /* + + Confirmed that order was partially executed. Next thing to do is to remember the trades and the new position. + + */ + + position.amountA = exchangePosition.amountA; + position.amountB = exchangePosition.amountB; + position.date = (new Date(exchangePosition.date)).valueOf(); + + applyTradesToContext(pTrades); + + let newTransaction = { + type: position.type + " partially executed", + position: position + }; + + context.executionContext.transactions.push(newTransaction); + + /* All done. */ + + next(); + + } catch (err) { + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + return; + } + } + function applyTradesToContext(pTrades) { try { diff --git a/this.config.json b/this.config.json index 3533409fe..d00fca406 100644 --- a/this.config.json +++ b/this.config.json @@ -47,13 +47,13 @@ "maxLogLoops": 5, "marketRateProvider": { "devTeam": "AAMasters", - "bot": "AAOlivia", + "bot": "AABruce", "botVersion": { "major": 1, "minor": 0 }, "product": "Candles", - "dataSet": "Multi-Period-Daily", + "dataSet": "One-Min", "dataSetVersion": "dataSet.V1" } } \ No newline at end of file