Half Iteration upgrading the Trading Engine (not running)
No files matched your search
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 5.6 KiB |
@@ -26,19 +26,19 @@ function newSessionFunctions() {
|
||||
'Exchange Account Asset->Asset->' +
|
||||
'Trading Strategy->' +
|
||||
'Trigger Stage->Trigger On Event->Trigger Off Event->Take Position Event->' +
|
||||
'Announcement->Formula->' +
|
||||
'Announcement->Announcement Formula->' +
|
||||
'Open Stage->Initial Definition->Open Execution->' +
|
||||
'Position Size->Position Rate->Formula->' +
|
||||
'Position Size In Base Asset->Position Size In Quoted Asset->Position Rate->Formula->' +
|
||||
'Initial Stop->Initial Take Profit->' +
|
||||
'Manage Stage->' +
|
||||
'Managed Stop Loss->Managed Take Profit->' +
|
||||
'Phase->Formula->Next Phase Event->Move To Phase Event->Phase->' +
|
||||
'Situation->Condition->Javascript Code->' +
|
||||
'Close Stage->Close Execution->' +
|
||||
'Announcement->Formula->' +
|
||||
'Announcement->Announcement Formula->' +
|
||||
'Execution Algorithm->Market Buy Order->Market Sell Order->Limit Buy Order->Limit Sell Order->' +
|
||||
'Create Order Event->Cancel Order Event->' +
|
||||
'Position Size->Position Rate->Formula->' +
|
||||
'Size In Base Asset->Size In Quoted Asset->Position Rate->Formula->' +
|
||||
'Situation->Condition->Javascript Code->' +
|
||||
'Market Order->Limit Order->' +
|
||||
'Simulated Exchange Events->Simulated Partial Fill->Simulated Actual Rate->Simulated Fees Paid->Formula->'
|
||||
@@ -49,9 +49,9 @@ function newSessionFunctions() {
|
||||
'Trading Engine->' +
|
||||
'Dynamic Indicators->Indicator Function->Formula->' +
|
||||
'Episode->Current->Last->Previous->' +
|
||||
'Episode Counters->Episode Statistics->' +
|
||||
'Episode Base Asset->Episode Quoted Asset->Episode Counters->Episode Statistics->' +
|
||||
'Periods->Strategies->Positions->Orders->Hits->Fails->' +
|
||||
'Profit Loss->Hit Ratio->Days->ROI->Anualized Rate Of Return->User Defined Statistic->' +
|
||||
'Profit Loss->Hit Ratio->Hit Fail->Days->ROI->Anualized Rate Of Return->User Defined Statistic->' +
|
||||
'Formula->' +
|
||||
'Candle->' +
|
||||
'Begin->End->Open->Close->Min->Max->Index->' +
|
||||
@@ -59,20 +59,23 @@ function newSessionFunctions() {
|
||||
'Distance To Event->' +
|
||||
'Trigger On->Trigger Off->Take Position->Close Position->Next Phase->Move To Phase->Create Order->Cancel Order->Close Order->' +
|
||||
'Strategy->' +
|
||||
'Serial Number->Identifier->Begin->End->Strategy Name->Index->Trigger Stage Status->Open Stage Status->Manage Stage Status->Close Stage Status->Status->Begin Rate->End Rate->Situation Name->' +
|
||||
'Serial Number->Identifier->Begin->End->Strategy Name->Index->Status->Begin Rate->End Rate->Situation Name->' +
|
||||
'Strategy Counters->Periods->' +
|
||||
'Position->' +
|
||||
'Serial Number->Identifier->Begin->End->Rate->Size->Open Stage Orders Size->Open Stage Filled Size->Close Stage Orders Size->Close Stage Filled Size->Exit Type->Status->Begin Rate->End Rate->Situation Name->' +
|
||||
'Serial Number->Identifier->Begin->End->Rate->Exit Type->Status->Begin Rate->End Rate->Situation Name->' +
|
||||
'Stop Loss->Stop Loss Stage->Stop Loss Phase->' +
|
||||
'Take Profit->Take Profit Stage->Take Profit Phase->' +
|
||||
'Position Counters->Periods->' +
|
||||
'Position Statistics->Profit Loss->Days->ROI->Hit Fail->User Defined Statistic->' +
|
||||
'Position Statistics->Days->User Defined Statistic->' +
|
||||
'Position Base Asset->Position Quoted Asset->Size->Profit Loss->ROI->Hit Fail->' +
|
||||
'Formula->' +
|
||||
'Exchange Orders->Market Buy Orders->Market Sell Orders->Limit Buy Orders->Limit Sell Orders->' +
|
||||
'Market Order->Limit Order->' +
|
||||
'Serial Number->Identifier->Exchange Id->Begin->End->Rate->Size->Exit Type->Status->Order Name->Algorithm Name->Situation Name->' +
|
||||
'Serial Number->Identifier->Exchange Id->Begin->End->Rate->Exit Type->Status->Order Name->Algorithm Name->Situation Name->Lock->' +
|
||||
'Order Counters->Periods->' +
|
||||
'Order Statistics->Size Filled->Percentage Filled->Amount Received->Actual Rate->Fees Paid->Days->User Defined Statistic->'
|
||||
'Order Base Asset->Order Quoted Asset->' +
|
||||
'Size->Size Filled->Fees Paid->' +
|
||||
'Order Statistics->Percentage Filled->Actual Rate->Days->User Defined Statistic->'
|
||||
|
||||
let tradingEngine = functionLibraryProtocolNode.getProtocolNode(node.tradingEngineReference.payload.referenceParent, false, true, true, false, false, lightingPath)
|
||||
|
||||
|
||||
@@ -153,13 +153,13 @@ function newPlotter() {
|
||||
|
||||
let minPositionPoint = {
|
||||
x: event.x,
|
||||
y: event.y + 2
|
||||
y: event.y + 4
|
||||
}
|
||||
minUserPositionRate = getRateFromPointAtBrowserCanvas(minPositionPoint, thisObject.container, coordinateSystem)
|
||||
|
||||
let maxPositionPoint = {
|
||||
x: event.x,
|
||||
y: event.y - 2
|
||||
y: event.y - 4
|
||||
}
|
||||
maxUserPositionRate = getRateFromPointAtBrowserCanvas(maxPositionPoint, thisObject.container, coordinateSystem)
|
||||
}
|
||||
|
||||
@@ -291,7 +291,12 @@ function newDesignSpace() {
|
||||
'market-order',
|
||||
'limit-order',
|
||||
'execution-algorithm',
|
||||
'cancel-order'
|
||||
'cancel-order',
|
||||
'limit-sell-order',
|
||||
'close-execution',
|
||||
'market-sell-order',
|
||||
'limit-buy-order',
|
||||
'market-buy-order'
|
||||
]
|
||||
|
||||
for (let i = 0; i < iconsNames.length; i++) {
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"type":"Data Mine","name":"Masters-Trading","config":"{ \n\"codeName\": \"Masters-Trading\"\n}","sensorBots":[],"indicatorBots":[],"tradingBots":[{"type":"Trading Bot","name":"Low Frequency","config":"{\n\"codeName\": \"Low-Frequency\"\n}","processes":[{"type":"Process Definition","name":"Trading","config":"{\n \"codeName\": \"Trading\",\n \"liveTradingWaitTime\": 0,\n \"paperTradingWaitTime\": 0,\n \"fordwardTestingWaitTime\": 0,\n \"backtestingWaitTime\": 0,\n \"sessionRunWaitTime\": 5000,\n \"retryWaitTime\": 10000,\n \"framework\": {\n \"name\": \"Low-Frequency-Trading-Process\"\n }\n }","processOutput":{"type":"Process Output","name":"New Process Output","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Episode Counters","id":"6fc3054e-5034-4fc7-bddf-02360e0a6acf","savedPayload":{"position":{"x":17450.068251326462,"y":15841.551559017382},"targetPosition":{"x":19639.44096944686,"y":14981.892188598802},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"db063d7b-db05-4bf6-941f-999e1ccb38fc"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Counters","id":"c3c2240f-514b-40de-825f-674037117d0b","savedPayload":{"position":{"x":17408.574644476477,"y":15727.325552793509},"targetPosition":{"x":19639.44096944686,"y":14981.892188598802},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"0764aaaf-d970-4f23-9df8-55fe5b7dd273"}}},{"type":"Output Dataset","name":"Multi-Period-Market Episode Statistics","id":"1dfdfc0d-842f-4e63-a591-256ac8a06b0f","savedPayload":{"position":{"x":17373.12088415627,"y":15611.394883926749},"targetPosition":{"x":19639.44096944686,"y":14981.892188598802},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"fc9dc0f7-35e0-4548-bb91-f920825d694f"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Statistics","id":"39360c55-5ba8-413b-b0bd-cac3789ebf5f","savedPayload":{"position":{"x":17343.701241214498,"y":15493.846491633021},"targetPosition":{"x":19639.44096944686,"y":14981.892188598802},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"91953362-8751-4440-a898-21245cd47c15"}}},{"type":"Output Dataset","name":"Multi-Period-Market Current Candle","id":"ba614415-6e4f-4979-97a5-34c72a59e67c","savedPayload":{"position":{"x":17320.378252589224,"y":15374.95820021913},"targetPosition":{"x":19639.44096944686,"y":14981.892188598802},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"17fb41f5-61b5-4433-9a10-950ff8216a7e"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Current Candle","id":"1a2e3461-33e6-45b1-bcc1-c56a8c5d275c","savedPayload":{"position":{"x":17303.209229100234,"y":15255.03551122105},"targetPosition":{"x":19639.44096944686,"y":14981.892188598802},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"bbc9467d-28bf-432b-9e49-582d1bcabfb9"}}},{"type":"Output Dataset","name":"Multi-Period-Market Current Balance","id":"567e4dc9-4deb-41e4-9ac9-dde943fb91ba","savedPayload":{"position":{"x":17292.23789362744,"y":15134.392617857315},"targetPosition":{"x":19639.44096944686,"y":14981.892188598802},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"acddff59-b51b-4b45-b58f-71d4077755ee"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Current Balance","id":"e94b9bb3-9f0c-4550-94e1-09de444780a8","savedPayload":{"position":{"x":17287.49247877813,"y":15013.347651781945},"targetPosition":{"x":19639.44096944686,"y":14981.892188598802},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"213b8fe8-f772-41ea-a3f5-97867be555f7"}}},{"type":"Output Dataset","name":"Multi-Period-Market Distance To Event","id":"a30e7306-7be9-41b6-a465-Line truncated
|
||||
{"type":"Data Mine","name":"Masters-Trading","config":"{ \n\"codeName\": \"Masters-Trading\"\n}","sensorBots":[],"indicatorBots":[],"tradingBots":[{"type":"Trading Bot","name":"Low Frequency","config":"{\n\"codeName\": \"Low-Frequency\"\n}","processes":[{"type":"Process Definition","name":"Trading","config":"{\n \"codeName\": \"Trading\",\n \"liveTradingWaitTime\": 0,\n \"paperTradingWaitTime\": 0,\n \"fordwardTestingWaitTime\": 0,\n \"backtestingWaitTime\": 0,\n \"sessionRunWaitTime\": 5000,\n \"retryWaitTime\": 10000,\n \"framework\": {\n \"name\": \"Low-Frequency-Trading-Process\"\n }\n }","processOutput":{"type":"Process Output","name":"New Process Output","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Episode Counters","id":"6fc3054e-5034-4fc7-bddf-02360e0a6acf","savedPayload":{"position":{"x":17438.417207713617,"y":15866.349209988648},"targetPosition":{"x":19618.046353341713,"y":14987.65120101664},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"db063d7b-db05-4bf6-941f-999e1ccb38fc"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Counters","id":"c3c2240f-514b-40de-825f-674037117d0b","savedPayload":{"position":{"x":17398.301373133007,"y":15759.474849835357},"targetPosition":{"x":19618.046353341713,"y":14987.65120101664},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"0764aaaf-d970-4f23-9df8-55fe5b7dd273"}}},{"type":"Output Dataset","name":"Multi-Period-Market Episode Statistics","id":"1dfdfc0d-842f-4e63-a591-256ac8a06b0f","savedPayload":{"position":{"x":17363.549519842163,"y":15651.186213779996},"targetPosition":{"x":19618.046353341713,"y":14987.65120101664},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"fc9dc0f7-35e0-4548-bb91-f920825d694f"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Statistics","id":"39360c55-5ba8-413b-b0bd-cac3789ebf5f","savedPayload":{"position":{"x":17334.098684478493,"y":15541.422909173882},"targetPosition":{"x":19618.046353341713,"y":14987.65120101664},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"91953362-8751-4440-a898-21245cd47c15"}}},{"type":"Output Dataset","name":"Multi-Period-Market Current Candle","id":"ba614415-6e4f-4979-97a5-34c72a59e67c","savedPayload":{"position":{"x":17309.99488261947,"y":15430.392081716627},"targetPosition":{"x":19618.046353341713,"y":14987.65120101664},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"17fb41f5-61b5-4433-9a10-950ff8216a7e"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Current Candle","id":"1a2e3461-33e6-45b1-bcc1-c56a8c5d275c","savedPayload":{"position":{"x":17291.28774353462,"y":15318.338854764093},"targetPosition":{"x":19618.046353341713,"y":14987.65120101664},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"bbc9467d-28bf-432b-9e49-582d1bcabfb9"}}},{"type":"Output Dataset","name":"Multi-Period-Market Current Balance","id":"567e4dc9-4deb-41e4-9ac9-dde943fb91ba","savedPayload":{"position":{"x":17278.01831081542,"y":15205.5193892544},"targetPosition":{"x":19618.046353341713,"y":14987.65120101664},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"acddff59-b51b-4b45-b58f-71d4077755ee"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Current Balance","id":"e94b9bb3-9f0c-4550-94e1-09de444780a8","savedPayload":{"position":{"x":17270.21631492878,"y":15092.194582295337},"targetPosition":{"x":19618.046353341713,"y":14987.65120101664},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"213b8fe8-f772-41ea-a3f5-97867be555f7"}}},{"type":"Output Dataset","name":"Multi-Period-Market Distance To Event","id":"a30e7306-7be9-41b6-a465-5Line truncated
|
||||
@@ -74,10 +74,20 @@
|
||||
async function createOrder(tradingSystemOrder, tradingEngineOrder) {
|
||||
|
||||
let price = tradingEngineOrder.rate.value // CCXT: how much quote currency you are willing to pay for a trade lot of base currency (for limit orders only)
|
||||
let amount = tradingEngineOrder.size.value // CCXT: how much of currency you want to trade
|
||||
let type // CCXT: a string literal type of order, ccxt currently unifies market and limit orders only
|
||||
let side // CCXT: a string literal for the direction of your order, buy or sell
|
||||
let symbol = bot.market.baseAsset + '/' + bot.market.quotedAsset // CCXT: a string literal symbol of the market you wish to trade on, like BTC/USD, ZEC/ETH, DOGE/DASH, etc
|
||||
let amount // CCXT: how much of currency you want to trade
|
||||
|
||||
/*
|
||||
We need at the amount a value denominated in Base Asset, if we do not
|
||||
have it, then we convert the value we have in Quoteed Asset.
|
||||
*/
|
||||
if (tradingEngineOrder.orderBaseAsset.size.value > 0) {
|
||||
amount = tradingEngineOrder.orderBaseAsset.size.value
|
||||
} else {
|
||||
amount = tradingEngineOrder.orderQuotedAsset.size.value / tradingEngineOrder.rate.value
|
||||
}
|
||||
|
||||
switch (tradingSystemOrder.type) {
|
||||
case 'Market Buy Order': {
|
||||
|
||||
@@ -43,11 +43,49 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
announcementsModule = undefined
|
||||
}
|
||||
|
||||
async function checkExecution(executionNode, stageIsOpening, stageIsClosing, stageSizeLimit, stageOrdersSize, stageFilledSize) {
|
||||
async function checkExecution(
|
||||
executionNode,
|
||||
stageIsOpening,
|
||||
stageIsClosing,
|
||||
stageSizeLimitInBaseAsset,
|
||||
stageSizeLimitInQuotedAsset,
|
||||
tradingEngineStage
|
||||
) {
|
||||
|
||||
/* Enforcing Precision Limit */
|
||||
stageSizeLimit.value = global.PRECISE(stageSizeLimit.value, 10)
|
||||
stageOrdersSize.value = global.PRECISE(stageOrdersSize.value, 10)
|
||||
/* Trading Stage Validations */
|
||||
if (tradingEngineStage.stageBaseAsset === undefined) { continue }
|
||||
if (tradingEngineStage.stageBaseAsset.size === undefined) { continue }
|
||||
if (tradingEngineStage.stageBaseAsset.sizeFilled === undefined) { continue }
|
||||
if (tradingEngineStage.stageBaseAsset.amountReceived === undefined) { continue }
|
||||
if (tradingEngineStage.stageBaseAsset.feesPaid === undefined) { continue }
|
||||
if (tradingEngineStage.stageQuotedAsset === undefined) { continue }
|
||||
if (tradingEngineStage.stageQuotedAsset.size === undefined) { continue }
|
||||
if (tradingEngineStage.stageQuotedAsset.sizeFilled === undefined) { continue }
|
||||
if (tradingEngineStage.stageQuotedAsset.amountReceived === undefined) { continue }
|
||||
if (tradingEngineStage.stageQuotedAsset.feesPaid === undefined) { continue }
|
||||
|
||||
/*
|
||||
The user choice of asset to define the size of the position,
|
||||
defines the asset that will track the information kept about the
|
||||
stage at the trading engine data structure. We set this asset
|
||||
to be used here in this way:
|
||||
*/
|
||||
let tradingEngineStageAsset
|
||||
if (tradingEngine.current.position.positionBaseAsset.size.value > 0) {
|
||||
tradingEngineStageAsset = tradingEngineStage.stageBaseAsset
|
||||
} else {
|
||||
tradingEngineStageAsset = tradingEngineStage.stageQuotedAsset
|
||||
}
|
||||
/*
|
||||
The asset type of the position size chosen by the user, also defines
|
||||
the stage limit to be on the same asset type.
|
||||
*/
|
||||
let stageSizeLimit
|
||||
if (tradingEngine.current.position.positionBaseAsset.size.value > 0) {
|
||||
stageSizeLimit = stageSizeLimitInBaseAsset
|
||||
} else {
|
||||
stageSizeLimit = stageSizeLimitInQuotedAsset
|
||||
}
|
||||
|
||||
await checkExecutionAlgorithms(executionNode)
|
||||
|
||||
@@ -79,7 +117,6 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
if (tradingEngineOrder.begin === undefined) { continue }
|
||||
if (tradingEngineOrder.end === undefined) { continue }
|
||||
if (tradingEngineOrder.rate === undefined) { continue }
|
||||
if (tradingEngineOrder.size === undefined) { continue }
|
||||
if (tradingEngineOrder.status === undefined) { continue }
|
||||
if (tradingEngineOrder.algorithmName === undefined) { continue }
|
||||
if (tradingEngineOrder.orderCounters === undefined) { continue }
|
||||
@@ -89,21 +126,55 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
if (tradingEngineOrder.orderStatistics.actualRate === undefined) { continue }
|
||||
if (tradingEngineOrder.orderStatistics.feesPaid === undefined) { continue }
|
||||
|
||||
if (tradingEngineOrder.orderBaseAsset.size === undefined) { continue }
|
||||
if (tradingEngineOrder.orderBaseAsset.sizeFilled === undefined) { continue }
|
||||
if (tradingEngineOrder.orderBaseAsset.amountReceived === undefined) { continue }
|
||||
if (tradingEngineOrder.orderBaseAsset.feesPaid === undefined) { continue }
|
||||
|
||||
if (tradingEngineOrder.orderQuotedAsset.size === undefined) { continue }
|
||||
if (tradingEngineOrder.orderQuotedAsset.sizeFilled === undefined) { continue }
|
||||
if (tradingEngineOrder.orderQuotedAsset.amountReceived === undefined) { continue }
|
||||
if (tradingEngineOrder.orderQuotedAsset.feesPaid === undefined) { continue }
|
||||
|
||||
/*
|
||||
The asset type of the position size chosen by the user, defines
|
||||
the asset at the order data strutcture where information is going to
|
||||
be stored.
|
||||
*/
|
||||
let traingEngineOrderAsset
|
||||
if (tradingEngine.current.position.positionBaseAsset.size.value > 0) {
|
||||
traingEngineOrderAsset = tradingEngineOrder.orderBaseAsset
|
||||
} else {
|
||||
traingEngineOrderAsset = tradingEngineOrder.orderQuotedAsset
|
||||
}
|
||||
|
||||
switch (tradingEngineOrder.status.value) {
|
||||
case 'Not Open': {
|
||||
{
|
||||
/* Check if we need to Create this Order */
|
||||
/* When the stage is closing we can not create new orders */
|
||||
if (stageIsClosing === true) { continue }
|
||||
/*
|
||||
Check if we can create an order based on the config value for spawnMultipleOrders.
|
||||
Trading System Orders that cannot spawn more than one Trading Engine Order needs to check if
|
||||
at the Trading Engine Order the lock is Open or Closed.
|
||||
*/
|
||||
if (tradingSystemOrder.config.spawnMultipleOrders !== true) {
|
||||
if (tradingEngineOrder.identifier.value === 'Closed') {
|
||||
continue
|
||||
}
|
||||
}
|
||||
/* Check if we need to Create this Order */
|
||||
let situationName = checkOrderEvent(tradingSystemOrder.createOrderEvent, tradingSystemOrder, executionAlgorithm, executionNode)
|
||||
if (situationName !== undefined) {
|
||||
|
||||
/* Open a new order */
|
||||
await openOrder(executionAlgorithm, tradingSystemOrder, tradingEngineOrder, situationName)
|
||||
await tryToOpenOrder(executionAlgorithm, tradingSystemOrder, tradingEngineOrder, situationName)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'Open': {
|
||||
/* Update this order properties */
|
||||
tradingEngineOrder.end.value = tradingEngine.current.candle.end.value
|
||||
tradingEngineOrder.orderCounters.periods.value++
|
||||
tradingEngineOrder.orderStatistics.days.value = tradingEngineOrder.orderCounters.periods.value * sessionParameters.timeFrame.config.value / global.ONE_DAY_IN_MILISECONDS
|
||||
@@ -114,13 +185,22 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
/* Check Events that happens at the Exchange, if needed. */
|
||||
await checkExchangeEvents(tradingSystemOrder, tradingEngineOrder)
|
||||
|
||||
/* If the stage is closing or the order is not still Open, we wont be cancelling orders based on defined events */
|
||||
/*
|
||||
In the previous steps, we might have discovered that the order was cancelled
|
||||
at the exchange, or filled, so the order might still not be Open.
|
||||
If the stage is closing or the order is not Open, we wont be cancelling orders
|
||||
based on defined events.
|
||||
*/
|
||||
if (stageIsClosing !== true && tradingEngineOrder.status.value === 'Open') {
|
||||
|
||||
/* Check if we need to Cancel this Order */
|
||||
let situationName = checkOrderEvent(tradingSystemOrder.cancelOrderEvent, tradingSystemOrder, executionAlgorithm, executionNode)
|
||||
if (situationName !== undefined) {
|
||||
|
||||
/* Simulate Order Cancelation, if needed. */
|
||||
simulateCancelOrder(tradingSystemOrder, tradingEngineOrder, 'Cancel Event')
|
||||
|
||||
/* Cancel the order at the Exchange, if needed. */
|
||||
await exchangeCancelOrder(tradingSystemOrder, tradingEngineOrder, 'Cancel Event')
|
||||
}
|
||||
}
|
||||
@@ -129,31 +209,24 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
}
|
||||
}
|
||||
|
||||
async function openOrder(executionAlgorithm, tradingSystemOrder, tradingEngineOrder, situationName) {
|
||||
/* Order Size Calculation */
|
||||
tradingEngineOrder.size.value = tradingSystem.formulas.get(executionAlgorithm.positionSize.formula.id) * tradingSystemOrder.config.positionSizePercentage / 100
|
||||
if (stageOrdersSize.value + tradingEngineOrder.size.value > stageSizeLimit.value) {
|
||||
/* We reduce the size to the remaining size of the position. */
|
||||
tradingEngineOrder.size.value = stageSizeLimit.value - stageOrdersSize.value
|
||||
tradingEngineOrder.size.value = global.PRECISE(tradingEngineOrder.size.value, 10)
|
||||
}
|
||||
async function tryToOpenOrder(executionAlgorithm, tradingSystemOrder, tradingEngineOrder, situationName) {
|
||||
|
||||
/* Check Order Size */
|
||||
if (tradingEngineOrder.size.value <= 0) { return }
|
||||
calculateOrderRate()
|
||||
calculateOrderSize()
|
||||
|
||||
/* Order Rate Calculation */
|
||||
tradingEngineOrder.rate.value = tradingEngine.current.position.rate.value // By default this is the order rate.
|
||||
if (tradingSystemOrder.positionRate !== undefined) {
|
||||
if (tradingSystemOrder.positionRate.formula !== undefined) {
|
||||
tradingEngineOrder.rate.value = tradingSystem.formulas.get(tradingSystemOrder.positionRate.formula.id)
|
||||
tradingEngineOrder.rate.value = global.PRECISE(tradingEngineOrder.rate.value, 10)
|
||||
}
|
||||
}
|
||||
/* Check Size: We are not going to create Orders which size is equal or less to zero. */
|
||||
if (traingEngineOrderAsset.size.value <= 0) { return }
|
||||
|
||||
/* Place Order at the Exchange */
|
||||
let result = await createOrderAtExchange(tradingSystemOrder, tradingEngineOrder)
|
||||
if (result !== true) { return }
|
||||
|
||||
/* Update Stage Counters */
|
||||
tradingEngineStage.stageBaseAsset.size.value = tradingEngineStage.stageBaseAsset.size.value + tradingEngineOrder.orderBaseAsset.size.value
|
||||
tradingEngineStage.stageBaseAsset.size.value = global.PRECISE(tradingEngineStage.stageBaseAsset.size.value, 10)
|
||||
tradingEngineStage.stageQuotedAsset.size.value = tradingEngineStage.stageQuotedAsset.size.value + tradingEngineOrder.orderQuotedAsset.size.value
|
||||
tradingEngineStage.stageQuotedAsset.size.value = global.PRECISE(tradingEngineStage.stageQuotedAsset.size.value, 10)
|
||||
|
||||
/* Updating Episode Counters */
|
||||
tradingEngine.episode.episodeCounters.orders.value++
|
||||
|
||||
@@ -170,34 +243,131 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
tradingEngineOrder.algorithmName.value = executionAlgorithm.name
|
||||
tradingEngineOrder.situationName.value = situationName
|
||||
|
||||
/* Update Stage Orders Size */
|
||||
stageOrdersSize.value = stageOrdersSize.value + tradingEngineOrder.size.value
|
||||
stageOrdersSize.value = global.PRECISE(stageOrdersSize.value, 10)
|
||||
}
|
||||
function calculateOrderRate() {
|
||||
/* Order Rate Calculation */
|
||||
tradingEngineOrder.rate.value = tradingEngine.current.position.rate.value // By default this is the order rate.
|
||||
if (tradingSystemOrder.positionRate !== undefined) {
|
||||
if (tradingSystemOrder.positionRate.formula !== undefined) {
|
||||
tradingEngineOrder.rate.value = tradingSystem.formulas.get(tradingSystemOrder.positionRate.formula.id)
|
||||
|
||||
async function createOrderAtExchange(tradingSystemOrder, tradingEngineOrder) {
|
||||
if (tradingEngineOrder.rate.value === undefined) {
|
||||
const errorText = 'Rate cannot be undefined. Fix this please.'
|
||||
tradingSystem.errors.push([tradingSystemOrder.positionRate.formula.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
|
||||
/* Filter by Session Type */
|
||||
switch (bot.SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
return true
|
||||
}
|
||||
case 'Live Trading Session': {
|
||||
break
|
||||
}
|
||||
case 'Fordward Testing Session': {
|
||||
break
|
||||
}
|
||||
case 'Paper Trading Session': {
|
||||
return true
|
||||
if (tradingEngineOrder.rate.value <= 0) {
|
||||
const errorText = 'Rate cannot be less or equal to zero. Fix this please.'
|
||||
tradingSystem.errors.push([tradingSystemOrder.positionRate.formula.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
tradingEngineOrder.rate.value = global.PRECISE(tradingEngineOrder.rate.value, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let orderId = await exchangeAPIModule.createOrder(tradingSystemOrder, tradingEngineOrder)
|
||||
function calculateOrderSize() {
|
||||
/*
|
||||
If the position size was defined in Base Asset, then
|
||||
the algorithm needs to define its size also in Base Asset.
|
||||
The same if it was deined in Quoted Asset.
|
||||
*/
|
||||
let sizeFormula
|
||||
if (tradingEngine.current.position.positionBaseAsset.size.value > 0) {
|
||||
/* Position was defined in Base Asset */
|
||||
if (executionAlgorithm.sizeInBaseAsset !== undefined) {
|
||||
if (executionAlgorithm.sizeInBaseAsset.formula !== undefined) {
|
||||
sizeFormula = executionAlgorithm.sizeInBaseAsset.formula
|
||||
} else {
|
||||
const errorText = 'Size In Base Asset needs a child Formula. Fix this please.'
|
||||
tradingSystem.errors.push([executionAlgorithm.sizeInBaseAsset.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
} else {
|
||||
const errorText = 'Execution Algorithm needs a child Size In Base Asset. Fix this please.'
|
||||
tradingSystem.errors.push([executionAlgorithm.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
} else {
|
||||
/* Position was defined in Quoted Asset */
|
||||
if (executionAlgorithm.sizeInQuotedAsset !== undefined) {
|
||||
if (executionAlgorithm.sizeInQuotedAsset.formula !== undefined) {
|
||||
sizeFormula = executionAlgorithm.sizeInQuotedAsset.formula
|
||||
} else {
|
||||
const errorText = 'Size In Quoted Asset needs a child Formula. Fix this please.'
|
||||
tradingSystem.errors.push([executionAlgorithm.sizeInQuotedAsset.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
} else {
|
||||
const errorText = 'Execution Algorithm needs a child Size In Quoted Asset. Fix this please.'
|
||||
tradingSystem.errors.push([executionAlgorithm.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
}
|
||||
|
||||
if (orderId !== undefined) {
|
||||
tradingEngineOrder.exchangeId.value = orderId
|
||||
return true
|
||||
/* Order Size Calculation */
|
||||
let algorithmSize = tradingSystem.formulas.get(sizeFormula.id)
|
||||
if (algorithmSize === undefined) {
|
||||
const errorText = 'Execution Algorithm Size cannot be undefined. Fix this please.'
|
||||
tradingSystem.errors.push([sizeFormula.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
|
||||
/* Validate that this config exists */
|
||||
if (tradingSystemOrder.config.positionSizePercentage === undefined) {
|
||||
const errorText = 'Config positionSizePercentage does not exist. Fix this please.'
|
||||
tradingSystem.errors.push([tradingSystemOrder.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
|
||||
traingEngineOrderAsset.size.value = algorithmSize * tradingSystemOrder.config.positionSizePercentage / 100
|
||||
traingEngineOrderAsset.size.value = global.PRECISE(traingEngineOrderAsset.size.value, 10)
|
||||
|
||||
/* Check against the Stage Size Limit */
|
||||
if (
|
||||
tradingEngineStageAsset.size.value + traingEngineOrderAsset.size.value > stageSizeLimit.value) {
|
||||
/* We reduce the size to the remaining size of the position. */
|
||||
traingEngineOrderAsset.size.value = stageSizeLimit.value - tradingEngineStageAsset.value
|
||||
traingEngineOrderAsset.size.value = global.PRECISE(traingEngineOrderAsset.size.value, 10)
|
||||
}
|
||||
|
||||
/* We are going to ESTIMATE the size in the oposite asset type, because we will need it later */
|
||||
switch (traingEngineOrderAsset.type) {
|
||||
case 'Order Base Asset': {
|
||||
tradingEngineOrder.orderQuotedAsset.size = tradingEngineOrder.orderBaseAsset.size * tradingEngineOrder.rate
|
||||
tradingEngineOrder.size.value = global.PRECISE(tradingEngineOrder.size.value, 10)
|
||||
}
|
||||
case 'Order Quoted Asset': {
|
||||
tradingEngineOrder.orderBaseAsset.size = tradingEngineOrder.orderQuotedAsset.size / tradingEngineOrder.rate
|
||||
tradingEngineOrder.size.value = global.PRECISE(tradingEngineOrder.size.value, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function createOrderAtExchange(tradingSystemOrder, tradingEngineOrder) {
|
||||
|
||||
/* Filter by Session Type */
|
||||
switch (bot.SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
return true
|
||||
}
|
||||
case 'Live Trading Session': {
|
||||
break
|
||||
}
|
||||
case 'Fordward Testing Session': {
|
||||
break
|
||||
}
|
||||
case 'Paper Trading Session': {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
let orderId = await exchangeAPIModule.createOrder(tradingSystemOrder, tradingEngineOrder)
|
||||
|
||||
if (orderId !== undefined) {
|
||||
tradingEngineOrder.exchangeId.value = orderId
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +392,7 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
/* Filter by what is defined at the Strategy */
|
||||
if (tradingSystemOrder.simulatedExchangeEvents === undefined) { return }
|
||||
|
||||
let previousSizeFilled = tradingEngineOrder.orderStatistics.sizeFilled.value
|
||||
let previousSizeFilled = tradingEngineOrderAsset.sizeFilled.value
|
||||
let previousPercentageFilled = tradingEngineOrder.orderStatistics.percentageFilled.value
|
||||
let previousAmountReceived = tradingEngineOrder.orderStatistics.amountReceived.value
|
||||
let previousFeesPaid = tradingEngineOrder.orderStatistics.feesPaid.value
|
||||
@@ -233,7 +403,7 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
sizeFilledSimulation()
|
||||
amountReceivedSimulation()
|
||||
|
||||
doTheAccounting(tradingSystemOrder, tradingEngineOrder, previousSizeFilled, previousPercentageFilled, previousAmountReceived, previousFeesPaid)
|
||||
doTheAccounting(tradingSystemOrder, tradingEngineOrder, previousSizeFilled, previousPercentageFilled, previousFeesPaid)
|
||||
|
||||
/* If the Stage is Closing and this order is still open, we need to cancel it now */
|
||||
if (stageIsClosing === true && tradingEngineOrder.status.value !== 'Closed') {
|
||||
@@ -443,129 +613,187 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
|
||||
function syncWithExchange(tradingSystemOrder, tradingEngineOrder, order) {
|
||||
|
||||
let previousSizeFilled = tradingEngineOrder.orderStatistics.sizeFilled.value
|
||||
let previousPercentageFilled = tradingEngineOrder.orderStatistics.percentageFilled.value
|
||||
let previousAmountReceived = tradingEngineOrder.orderStatistics.amountReceived.value
|
||||
let previousFeesPaid = tradingEngineOrder.orderStatistics.feesPaid.value
|
||||
let previousBaseAssetSizeFilled = tradingEngineOrder.orderBaseAsset.sizeFilled.value
|
||||
let previousQuotedAssetSizeFilled = tradingEngineOrder.orderQuotedAsset.sizeFilled.value
|
||||
let previousBaseAssetFeesPaid = tradingEngineOrder.orderBaseAsset.feesPaid.value
|
||||
let previousQuotedAssetFeesPaid = tradingEngineOrder.orderQuotedAsset.feesPaid.value
|
||||
|
||||
/* Fees Paid */
|
||||
tradingEngineOrder.orderStatistics.feesPaid.value = tradingEngineOrder.size.value - order.amount
|
||||
tradingEngineOrder.orderStatistics.feesPaid.value = global.PRECISE(tradingEngineOrder.orderStatistics.feesPaid.value, 10)
|
||||
|
||||
/* Percentage Filled */
|
||||
tradingEngineOrder.orderStatistics.percentageFilled.value = order.filled * 100 / (order.filled + order.remaining)
|
||||
tradingEngineOrder.orderStatistics.percentageFilled.value = global.PRECISE(tradingEngineOrder.orderStatistics.percentageFilled.value, 10)
|
||||
|
||||
/* Size Filled */
|
||||
tradingEngineOrder.orderStatistics.sizeFilled.value = order.filled
|
||||
tradingEngineOrder.orderStatistics.sizeFilled.value = global.PRECISE(tradingEngineOrder.orderStatistics.sizeFilled.value, 10)
|
||||
|
||||
/* Amount Received */
|
||||
tradingEngineOrder.orderStatistics.amountReceived.value = order.cost
|
||||
tradingEngineOrder.orderStatistics.amountReceived.value = global.PRECISE(tradingEngineOrder.orderStatistics.amountReceived.value, 10)
|
||||
|
||||
/* Actual Rate */
|
||||
/* Actual Rate Calculation */
|
||||
tradingEngineOrder.orderStatistics.actualRate.value = order.price
|
||||
tradingEngineOrder.orderStatistics.actualRate.value = global.PRECISE(tradingEngineOrder.orderStatistics.actualRate.value, 10)
|
||||
|
||||
doTheAccounting(tradingSystemOrder, tradingEngineOrder, previousSizeFilled, previousPercentageFilled, previousAmountReceived, previousFeesPaid)
|
||||
/* Fees Paid Calculation */
|
||||
/*
|
||||
As a response from the exchange we can not always get the fees.
|
||||
For that reason we need to estimate them base of the information that we do have.
|
||||
CCXT provides order.amount which represents the size we set for the order minus the
|
||||
fees taken by the exchange, all denominated in Base Asset.
|
||||
In this way if we substract to the order size this order.amount
|
||||
we can get the fees. All this is denominated in base asset because that is how CCXT works.
|
||||
The fees then can be estimated in Quoted Asset using the Actual Rate.
|
||||
*/
|
||||
tradingEngineOrder.orderBaseAsset.feesPaid.value = tradingEngineOrder.orderBaseAsset.size.value - order.amount
|
||||
tradingEngineOrder.orderBaseAsset.feesPaid.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.feesPaid.value, 10)
|
||||
tradingEngineOrder.orderQuotedAsset.feesPaid.value = tradingEngineOrder.orderBaseAsset.feesPaid.value * tradingEngineOrder.orderStatistics.actualRate.value
|
||||
tradingEngineOrder.orderQuotedAsset.feesPaid.value = global.PRECISE(tradingEngineOrder.orderQuotedAsset.feesPaid.value, 10)
|
||||
|
||||
/* Percentage Filled Calculation */
|
||||
tradingEngineOrder.orderStatistics.percentageFilled.value = order.filled * 100 / (order.filled + order.remaining)
|
||||
tradingEngineOrder.orderStatistics.percentageFilled.value = global.PRECISE(tradingEngineOrder.orderStatistics.percentageFilled.value, 10)
|
||||
|
||||
/* Size Filled Calculation */
|
||||
/*
|
||||
CCXT returns order.filled with an amount denominated in Base Asset. We will
|
||||
take it from there for our Order Base Asset. For our Order Quoted Asset we
|
||||
will use the field order.cost.
|
||||
*/
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value = order.filled
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.sizeFilled.value, 10)
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value = order.cost
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value = global.PRECISE(tradingEngineOrder.orderQuotedAsset.sizeFilled.value, 10)
|
||||
|
||||
doTheAccounting(
|
||||
tradingSystemOrder,
|
||||
tradingEngineOrder,
|
||||
previousBaseAssetSizeFilled,
|
||||
previousQuotedAssetSizeFilled,
|
||||
previousBaseAssetFeesPaid,
|
||||
previousQuotedAssetFeesPaid
|
||||
)
|
||||
}
|
||||
|
||||
function doTheAccounting(tradingSystemOrder, tradingEngineOrder, previousSizeFilled, previousPercentageFilled, previousAmountReceived, previousFeesPaid) {
|
||||
function doTheAccounting(
|
||||
tradingSystemOrder,
|
||||
tradingEngineOrder,
|
||||
previousBaseAssetSizeFilled,
|
||||
previousQuotedAssetSizeFilled,
|
||||
previousBaseAssetFeesPaid,
|
||||
previousQuotedAssetFeesPaid
|
||||
) {
|
||||
|
||||
/* Unaccount for the previous Stage Filled Size */
|
||||
stageFilledSize.value = stageFilledSize.value - tradingEngineOrder.size.value * previousPercentageFilled / 100
|
||||
/* Account for the current Stage Filled Size */
|
||||
stageFilledSize.value = stageFilledSize.value + tradingEngineOrder.size.value * tradingEngineOrder.orderStatistics.percentageFilled.value / 100
|
||||
stageFilledSize.value = global.PRECISE(stageFilledSize.value, 10)
|
||||
updateStageAssets()
|
||||
updateBalances()
|
||||
|
||||
function updateStageAssets() {
|
||||
/* Stage Base Asset: Undo the previous accounting */
|
||||
tradingEngineStage.stageBaseAsset.sizeFilled.value =
|
||||
tradingEngineStage.stageBaseAsset.value -
|
||||
previousBaseAssetSizeFilled
|
||||
|
||||
/* Balances Update */
|
||||
switch (true) {
|
||||
case tradingSystemOrder.type === 'Market Buy Order' || tradingSystemOrder.type === 'Limit Buy Order': {
|
||||
tradingEngineStage.stageBaseAsset.feesPaid.value =
|
||||
tradingEngineStage.feesPaid.value -
|
||||
previousBaseAssetFeesPaid
|
||||
|
||||
/* Undo the previous accounting */
|
||||
tradingEngine.current.balance.baseAsset.value = tradingEngine.current.balance.baseAsset.value - previousFeesPaid - previousSizeFilled
|
||||
/* Account the current filling and fees */
|
||||
tradingEngine.current.balance.baseAsset.value = tradingEngine.current.balance.baseAsset.value + tradingEngineOrder.orderStatistics.sizeFilled.value + tradingEngineOrder.orderStatistics.feesPaid.value
|
||||
/* Stage Base Asset: Account the current filling and fees */
|
||||
tradingEngineStage.stageBaseAsset.sizeFilled.value =
|
||||
tradingEngineStage.stageBaseAsset.value +
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value
|
||||
|
||||
/* Undo the previous accounting */
|
||||
tradingEngine.current.balance.quotedAsset.value = tradingEngine.current.balance.quotedAsset.value + previousAmountReceived
|
||||
/* Account the current filling and fees */
|
||||
tradingEngine.current.balance.quotedAsset.value = tradingEngine.current.balance.quotedAsset.value - tradingEngineOrder.orderStatistics.amountReceived.value
|
||||
tradingEngineStage.stageBaseAsset.feesPaid.value =
|
||||
tradingEngineStage.feesPaid.value +
|
||||
tradingEngineOrder.orderBaseAsset.feesPaid.value
|
||||
|
||||
break
|
||||
}
|
||||
case tradingSystemOrder.type === 'Market Sell Order' || tradingSystemOrder.type === 'Limit Sell Order': {
|
||||
/* Stage Quote Asset: Undo the previous accounting */
|
||||
tradingEngineStage.stageQuotedAsset.sizeFilled.value =
|
||||
tradingEngineStage.stageQuotedAsset.value -
|
||||
previousQuotedAssetSizeFilled
|
||||
|
||||
/* Undo the previous accounting */
|
||||
tradingEngine.current.balance.baseAsset.value = tradingEngine.current.balance.baseAsset.value + previousFeesPaid + previousSizeFilled
|
||||
/* Account the current filling and fees */
|
||||
tradingEngine.current.balance.baseAsset.value = tradingEngine.current.balance.baseAsset.value - tradingEngineOrder.orderStatistics.sizeFilled.value - tradingEngineOrder.orderStatistics.feesPaid.value
|
||||
tradingEngineStage.stageQuotedAsset.feesPaid.value =
|
||||
tradingEngineStage.feesPaid.value -
|
||||
previousQuotedAssetFeesPaid
|
||||
|
||||
/* Undo the previous accounting */
|
||||
tradingEngine.current.balance.quotedAsset.value = tradingEngine.current.balance.quotedAsset.value - previousAmountReceived
|
||||
/* Account the current filling and fees */
|
||||
tradingEngine.current.balance.quotedAsset.value = tradingEngine.current.balance.quotedAsset.value + tradingEngineOrder.orderStatistics.amountReceived.value
|
||||
/* Stage Quote Asset: Account the current filling and fees */
|
||||
tradingEngineStage.stageQuotedAsset.sizeFilled.value =
|
||||
tradingEngineStage.stageQuotedAsset.value +
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
tradingEngineStage.stageQuotedAsset.feesPaid.value =
|
||||
tradingEngineStage.feesPaid.value +
|
||||
tradingEngineOrder.orderQuotedAsset.feesPaid.value
|
||||
|
||||
function simulateCancelOrder(tradingSystemOrder, tradingEngineOrder, exitType) {
|
||||
tradingEngineStage.stageBaseAsset.sizeFilled.value = global.PRECISE(tradingEngineStage.stageBaseAsset.sizeFilled.value, 10)
|
||||
tradingEngineStage.stageBaseAsset.feesPaid.value = global.PRECISE(tradingEngineStage.stageBaseAsset.feesPaid.value, 10)
|
||||
|
||||
/* Filter by Session Type */
|
||||
switch (bot.SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
break
|
||||
}
|
||||
case 'Live Trading Session': {
|
||||
return
|
||||
}
|
||||
case 'Fordward Testing Session': {
|
||||
return
|
||||
}
|
||||
case 'Paper Trading Session': {
|
||||
break
|
||||
}
|
||||
tradingEngineStage.stageQuotedAsset.sizeFilled.value = global.PRECISE(tradingEngineStage.stageQuotedAsset.sizeFilled.value, 10)
|
||||
tradingEngineStage.stageQuotedAsset.feesPaid.value = global.PRECISE(tradingEngineStage.stageQuotedAsset.feesPaid.value, 10)
|
||||
}
|
||||
|
||||
/* Close this Order */
|
||||
tradingEngineOrder.status.value = 'Closed'
|
||||
tradingEngineOrder.exitType.value = exitType
|
||||
function updateBalances() {
|
||||
/* Balances Update */
|
||||
switch (true) {
|
||||
case tradingSystemOrder.type === 'Market Buy Order' || tradingSystemOrder.type === 'Limit Buy Order': {
|
||||
|
||||
/* Initialize this */
|
||||
tradingEngine.current.distanceToEvent.closeOrder.value = 1
|
||||
/* Balance Base Asset: Undo the previous accounting */
|
||||
tradingEngine.current.balance.baseAsset.value =
|
||||
tradingEngine.current.balance.baseAsset.value -
|
||||
previousBaseAssetSizeFilled
|
||||
|
||||
/* Since the order was cancelled, we remove the unfilled amount of the order from here */
|
||||
let unfilledPercentage = 100 - tradingEngineOrder.orderStatistics.percentageFilled.value
|
||||
let unfilledSize = tradingEngineOrder.size.value * unfilledPercentage / 100
|
||||
stageOrdersSize.value = stageOrdersSize.value - unfilledSize
|
||||
stageOrdersSize.value = global.PRECISE(stageOrdersSize.value, 10)
|
||||
}
|
||||
/* Balance Base Asset: Account the current filling and fees */
|
||||
tradingEngine.current.balance.baseAsset.value =
|
||||
tradingEngine.current.balance.baseAsset.value +
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value
|
||||
|
||||
async function exchangeCancelOrder(tradingSystemOrder, tradingEngineOrder, exitType) {
|
||||
/* Balance Quoted Asset: Undo the previous accounting */
|
||||
tradingEngine.current.balance.quotedAsset.value =
|
||||
tradingEngine.current.balance.quotedAsset.value +
|
||||
previousQuotedAssetSizeFilled +
|
||||
previousQuotedAssetFeesPaid
|
||||
|
||||
/* Filter by Session Type */
|
||||
switch (bot.SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
return
|
||||
}
|
||||
case 'Live Trading Session': {
|
||||
break
|
||||
}
|
||||
case 'Fordward Testing Session': {
|
||||
break
|
||||
}
|
||||
case 'Paper Trading Session': {
|
||||
return
|
||||
/* Balance Quoted Asset: Account the current filling and fees */
|
||||
tradingEngine.current.balance.quotedAsset.value =
|
||||
tradingEngine.current.balance.quotedAsset.value -
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value -
|
||||
tradingEngineOrder.orderQuotedAsset.feesPaid.value
|
||||
break
|
||||
}
|
||||
case tradingSystemOrder.type === 'Market Sell Order' || tradingSystemOrder.type === 'Limit Sell Order': {
|
||||
|
||||
/* Balance Base Asset: Undo the previous accounting */
|
||||
tradingEngine.current.balance.baseAsset.value =
|
||||
tradingEngine.current.balance.baseAsset.value +
|
||||
previousBaseAssetSizeFilled +
|
||||
previousBaseAssetFeesPaid
|
||||
|
||||
/* Balance Base Asset: Account the current filling and fees */
|
||||
tradingEngine.current.balance.baseAsset.value =
|
||||
tradingEngine.current.balance.baseAsset.value -
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value -
|
||||
tradingEngineOrder.orderBaseAsset.feesPaid.value
|
||||
|
||||
/* Balance Quoted Asset: Undo the previous accounting */
|
||||
tradingEngine.current.balance.quotedAsset.value =
|
||||
tradingEngine.current.balance.quotedAsset.value -
|
||||
previousQuotedAssetSizeFilled
|
||||
|
||||
/* Balance Quoted Asset: Account the current filling and fees */
|
||||
tradingEngine.current.balance.quotedAsset.value =
|
||||
tradingEngine.current.balance.quotedAsset.value +
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value
|
||||
break
|
||||
}
|
||||
}
|
||||
tradingEngine.current.balance.baseAsset.value = global.PRECISE(tradingEngine.current.balance.baseAsset.value, 10)
|
||||
tradingEngine.current.balance.quotedAsset.value = global.PRECISE(tradingEngine.current.balance.quotedAsset.value, 10)
|
||||
}
|
||||
|
||||
/* Check if we can cancel the order at the Exchange. */
|
||||
let result = await exchangeAPIModule.cancelOrder(tradingSystemOrder, tradingEngineOrder)
|
||||
if (result === true) {
|
||||
function simulateCancelOrder(tradingSystemOrder, tradingEngineOrder, exitType) {
|
||||
|
||||
/* Filter by Session Type */
|
||||
switch (bot.SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
break
|
||||
}
|
||||
case 'Live Trading Session': {
|
||||
return
|
||||
}
|
||||
case 'Fordward Testing Session': {
|
||||
return
|
||||
}
|
||||
case 'Paper Trading Session': {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/* Close this Order */
|
||||
tradingEngineOrder.status.value = 'Closed'
|
||||
tradingEngineOrder.exitType.value = exitType
|
||||
@@ -578,45 +806,80 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
let unfilledSize = tradingEngineOrder.size.value * unfilledPercentage / 100
|
||||
stageOrdersSize.value = stageOrdersSize.value - unfilledSize
|
||||
stageOrdersSize.value = global.PRECISE(stageOrdersSize.value, 10)
|
||||
|
||||
/*
|
||||
Perhaps the order was filled a bit more between the last time we checked and when it was cancelled.
|
||||
To sync our accounting, we need to check the order one last time and if it changed, fix it.
|
||||
*/
|
||||
|
||||
let order = await exchangeAPIModule.getOrder(tradingSystemOrder, tradingEngineOrder)
|
||||
|
||||
if (order === undefined) { return }
|
||||
|
||||
syncWithExchange(tradingSystemOrder, tradingEngineOrder, order)
|
||||
}
|
||||
}
|
||||
|
||||
function checkOrderEvent(event, order, executionAlgorithm, executionNode) {
|
||||
if (event !== undefined) {
|
||||
for (let k = 0; k < event.situations.length; k++) {
|
||||
let situation = event.situations[k]
|
||||
let passed
|
||||
if (situation.conditions.length > 0) {
|
||||
passed = true
|
||||
async function exchangeCancelOrder(tradingSystemOrder, tradingEngineOrder, exitType) {
|
||||
|
||||
/* Filter by Session Type */
|
||||
switch (bot.SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
return
|
||||
}
|
||||
case 'Live Trading Session': {
|
||||
break
|
||||
}
|
||||
case 'Fordward Testing Session': {
|
||||
break
|
||||
}
|
||||
case 'Paper Trading Session': {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
passed = tradingSystem.checkConditions(situation, passed)
|
||||
/* Check if we can cancel the order at the Exchange. */
|
||||
let result = await exchangeAPIModule.cancelOrder(tradingSystemOrder, tradingEngineOrder)
|
||||
if (result === true) {
|
||||
/* Close this Order */
|
||||
tradingEngineOrder.status.value = 'Closed'
|
||||
tradingEngineOrder.exitType.value = exitType
|
||||
|
||||
tradingSystem.values.push([situation.id, passed])
|
||||
if (passed) {
|
||||
tradingSystem.highlights.push(situation.id)
|
||||
tradingSystem.highlights.push(event.id)
|
||||
tradingSystem.highlights.push(order.id)
|
||||
tradingSystem.highlights.push(executionAlgorithm.id)
|
||||
tradingSystem.highlights.push(executionNode.id)
|
||||
/* Initialize this */
|
||||
tradingEngine.current.distanceToEvent.closeOrder.value = 1
|
||||
|
||||
announcementsModule.makeAnnoucements(event)
|
||||
return situation.name // if the event is triggered, we return the name of the situation that passed
|
||||
/* Since the order was cancelled, we remove the unfilled amount of the order from here */
|
||||
let unfilledPercentage = 100 - tradingEngineOrder.orderStatistics.percentageFilled.value
|
||||
let unfilledSize = tradingEngineOrder.size.value * unfilledPercentage / 100
|
||||
stageOrdersSize.value = stageOrdersSize.value - unfilledSize
|
||||
stageOrdersSize.value = global.PRECISE(stageOrdersSize.value, 10)
|
||||
|
||||
/*
|
||||
Perhaps the order was filled a bit more between the last time we checked and when it was cancelled.
|
||||
To sync our accounting, we need to check the order one last time and if it changed, fix it.
|
||||
*/
|
||||
|
||||
let order = await exchangeAPIModule.getOrder(tradingSystemOrder, tradingEngineOrder)
|
||||
|
||||
if (order === undefined) { return }
|
||||
|
||||
syncWithExchange(tradingSystemOrder, tradingEngineOrder, order)
|
||||
}
|
||||
}
|
||||
|
||||
function checkOrderEvent(event, order, executionAlgorithm, executionNode) {
|
||||
if (event !== undefined) {
|
||||
for (let k = 0; k < event.situations.length; k++) {
|
||||
let situation = event.situations[k]
|
||||
let passed
|
||||
if (situation.conditions.length > 0) {
|
||||
passed = true
|
||||
}
|
||||
|
||||
passed = tradingSystem.checkConditions(situation, passed)
|
||||
|
||||
tradingSystem.values.push([situation.id, passed])
|
||||
if (passed) {
|
||||
tradingSystem.highlights.push(situation.id)
|
||||
tradingSystem.highlights.push(event.id)
|
||||
tradingSystem.highlights.push(order.id)
|
||||
tradingSystem.highlights.push(executionAlgorithm.id)
|
||||
tradingSystem.highlights.push(executionNode.id)
|
||||
|
||||
announcementsModule.makeAnnoucements(event)
|
||||
return situation.name // if the event is triggered, we return the name of the situation that passed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
applySlippageToTakeProfit: applySlippageToTakeProfit,
|
||||
updateStopLoss: updateStopLoss,
|
||||
updateTakeProfit: updateTakeProfit,
|
||||
updateSizeAndRate: updateSizeAndRate,
|
||||
initializeSizeAndRate: initializeSizeAndRate,
|
||||
updateEnds: updateEnds,
|
||||
updateStatus: updateStatus,
|
||||
updateCounters: updateCounters,
|
||||
@@ -41,18 +41,26 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
}
|
||||
|
||||
function openPosition(situationName) {
|
||||
|
||||
/* Recording the opening at the Trading Engine Data Structure */
|
||||
tradingEngine.current.position.status.value = 'Open'
|
||||
tradingEngine.current.position.serialNumber.value = tradingEngine.episode.episodeCounters.positions.value
|
||||
tradingEngine.current.position.identifier.value = global.UNIQUE_ID()
|
||||
tradingEngine.current.position.begin.value = tradingEngine.current.candle.begin.value
|
||||
tradingEngine.current.position.end.value = tradingEngine.current.candle.end.value
|
||||
|
||||
tradingEngine.current.position.situationName.value = situationName
|
||||
|
||||
/* Initializing Stop and Take Profit Stage / Phase */
|
||||
tradingEngine.current.position.stopLoss.stopLossStage.value = 'Open Stage'
|
||||
tradingEngine.current.position.takeProfit.takeProfitStage.value = 'Open Stage'
|
||||
tradingEngine.current.position.stopLoss.stopLossPhase.value = 0
|
||||
tradingEngine.current.position.takeProfit.takeProfitPhase.value = 0
|
||||
|
||||
/* Updating Episode Counters */
|
||||
tradingEngine.episode.episodeCounters.positions.value++
|
||||
|
||||
/* Inicializing this counter */
|
||||
tradingEngine.current.distanceToEvent.takePosition.value = 1
|
||||
}
|
||||
|
||||
function closingPosition(exitType) {
|
||||
@@ -91,11 +99,84 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
tradingEngine.current.position.takeProfit.takeProfitStage.value = stage
|
||||
}
|
||||
|
||||
function updateSizeAndRate(size, rate) {
|
||||
tradingEngine.current.position.size.value = global.PRECISE(size, 10)
|
||||
tradingEngine.current.position.rate.value = global.PRECISE(rate, 10)
|
||||
function initializeSizeAndRate() {
|
||||
|
||||
setPositionSize()
|
||||
setPositionRate()
|
||||
|
||||
tradingEngine.current.position.beginRate.value = tradingEngine.current.position.rate.value
|
||||
|
||||
function setPositionSize() {
|
||||
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
|
||||
|
||||
/* Basic Validation */
|
||||
if (
|
||||
strategy.openStage.initialDefinition.positionSizeInBaseAsset !== undefined &&
|
||||
strategy.openStage.initialDefinition.positionSizeInQuotedAsset !== undefined
|
||||
) {
|
||||
const errorText = 'Only Position Size In Base Asset or Position Size In Quoted Asset is allowed. Remove one of them please.'
|
||||
tradingSystem.errors.push([strategy.openStage.initialDefinition.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
|
||||
/* Position In Base Asset */
|
||||
if (strategy.openStage.initialDefinition.positionSizeInBaseAsset !== undefined) {
|
||||
if (strategy.openStage.initialDefinition.positionSizeInBaseAsset.formula !== undefined) {
|
||||
let value = tradingSystem.formulas.get(strategy.openStage.initialDefinition.positionSizeInBaseAsset.formula.id)
|
||||
if (value === undefined) {
|
||||
const errorText = 'Position Size In Base Asset cannot be undefined. Fix this please.'
|
||||
tradingSystem.errors.push([strategy.openStage.initialDefinition.positionSizeInBaseAsset.formula.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
if (value === undefined) {
|
||||
const errorText = 'Position Size In Base Asset cannot be zero. Fix this please.'
|
||||
tradingSystem.errors.push([strategy.openStage.initialDefinition.positionSizeInBaseAsset.formula.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
tradingEngine.current.position.positionBaseAsset.size.value = global.PRECISE(value, 10)
|
||||
} else {
|
||||
const errorText = 'You need to specify a Formula for this.'
|
||||
tradingSystem.errors.push([strategy.openStage.initialDefinition.positionSizeInBaseAsset.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
}
|
||||
|
||||
/* Position In Quoted Asset */
|
||||
if (strategy.openStage.initialDefinition.positionSizeInQuotedAsset !== undefined) {
|
||||
if (strategy.openStage.initialDefinition.positionSizeInQuotedAsset.formula !== undefined) {
|
||||
let value = tradingSystem.formulas.get(strategy.openStage.initialDefinition.positionSizeInQuotedAsset.formula.id)
|
||||
if (value === undefined) {
|
||||
const errorText = 'Position Size In Quoted Asset cannot be undefined. Fix this please.'
|
||||
tradingSystem.errors.push([strategy.openStage.initialDefinition.positionSizeInQuotedAsset.formula.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
if (value === undefined) {
|
||||
const errorText = 'Position Size In Quoted Asset cannot be zero. Fix this please.'
|
||||
tradingSystem.errors.push([strategy.openStage.initialDefinition.positionSizeInQuotedAsset.formula.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
tradingEngine.current.position.positionQuotedAsset.size.value = global.PRECISE(value, 10)
|
||||
} else {
|
||||
const errorText = 'You need to specify a Formula for this.'
|
||||
tradingSystem.errors.push([strategy.openStage.initialDefinition.positionSizeInQuotedAsset.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setPositionRate() {
|
||||
const DEFAULT_VALUE = tradingEngine.current.candle.close.value
|
||||
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
|
||||
|
||||
if (strategy.openStage === undefined) return DEFAULT_VALUE
|
||||
if (strategy.openStage.initialDefinition === undefined) return DEFAULT_VALUE
|
||||
if (strategy.openStage.initialDefinition.positionRate === undefined) return DEFAULT_VALUE
|
||||
if (strategy.openStage.initialDefinition.positionRate.formula === undefined) return DEFAULT_VALUE
|
||||
|
||||
let value = tradingSystem.formulas.get(strategy.openStage.initialDefinition.positionRate.formula.id)
|
||||
if (value === undefined) return DEFAULT_VALUE
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
function preventStopLossDistortion() {
|
||||
@@ -182,14 +263,42 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
}
|
||||
|
||||
function updateStatistics() {
|
||||
|
||||
if (bot.sessionAndMarketBaseAssetsAreEqual) {
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value = tradingEngine.current.balance.baseAsset.value - tradingEngine.previous.balance.baseAsset.value
|
||||
tradingEngine.current.position.positionStatistics.ROI.value = tradingEngine.current.position.positionStatistics.profitLoss.value * 100 / tradingEngine.current.position.size.value
|
||||
/* Profit Loss Calculation */
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value =
|
||||
tradingEngine.current.balance.baseAsset.value -
|
||||
tradingEngine.previous.balance.baseAsset.value +
|
||||
tradingEngine.current.balance.quotedAsset.value / tradingEngine.current.position.endRate.value -
|
||||
tradingEngine.previous.balance.quotedAsset.value / tradingEngine.current.position.beginRate.value
|
||||
|
||||
/* ROI Calculation */
|
||||
tradingEngine.current.position.positionStatistics.ROI.value =
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value * 100 /
|
||||
tradingEngine.current.position.size.value
|
||||
} else {
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value = tradingEngine.current.balance.quotedAsset.value - tradingEngine.previous.balance.quotedAsset.value
|
||||
tradingEngine.current.position.positionStatistics.ROI.value = tradingEngine.current.position.positionStatistics.profitLoss.value * 100 / tradingEngine.current.position.size.value
|
||||
/* Profit Loss Calculation */
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value =
|
||||
tradingEngine.current.balance.baseAsset.value * tradingEngine.current.position.endRate.value -
|
||||
tradingEngine.previous.balance.baseAsset.value * tradingEngine.current.position.beginRate.value +
|
||||
tradingEngine.current.balance.quotedAsset.value -
|
||||
tradingEngine.previous.balance.quotedAsset.value
|
||||
|
||||
/* ROI Calculation */
|
||||
tradingEngine.current.position.positionStatistics.ROI.value =
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value * 100 /
|
||||
(tradingEngine.current.position.size.value * tradingEngine.current.position.beginRate.value)
|
||||
}
|
||||
tradingEngine.current.position.positionStatistics.days.value = tradingEngine.current.position.positionCounters.periods.value * sessionParameters.timeFrame.config.value / global.ONE_DAY_IN_MILISECONDS
|
||||
|
||||
/* Days Calculation */
|
||||
tradingEngine.current.position.positionStatistics.days.value = tradingEngine.current.position.positionCounters.periods.value *
|
||||
sessionParameters.timeFrame.config.value / global.ONE_DAY_IN_MILISECONDS
|
||||
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value = global.PRECISE(tradingEngine.current.position.positionStatistics.profitLoss.value, 10)
|
||||
tradingEngine.current.position.positionStatistics.ROI.value = global.PRECISE(tradingEngine.current.position.positionStatistics.ROI.value, 10)
|
||||
tradingEngine.current.position.positionStatistics.days.value = global.PRECISE(tradingEngine.current.position.positionStatistics.days.value, 10)
|
||||
|
||||
/* Hit Fail Calculation */
|
||||
if (tradingEngine.current.position.positionStatistics.ROI.value > 0) {
|
||||
tradingEngine.current.position.positionStatistics.hitFail.value = 'HIT'
|
||||
} else {
|
||||
|
||||
@@ -63,22 +63,28 @@ exports.newTradingStrategy = function newTradingStrategy(bot, logger, tradingEng
|
||||
}
|
||||
}
|
||||
|
||||
function updateStageStatus(stage, status) {
|
||||
function updateStageStatus(stage, status, exitType) {
|
||||
switch (stage) {
|
||||
case 'Trigger Stage': {
|
||||
tradingEngine.current.strategy.triggerStageStatus.value = status
|
||||
tradingEngine.current.strategyTriggerStage.status.value = status
|
||||
break
|
||||
}
|
||||
case 'Open Stage': {
|
||||
tradingEngine.current.strategy.openStageStatus.value = status
|
||||
tradingEngine.current.strategyOpenStage.status.value = status
|
||||
if (exitType !== undefined) {
|
||||
tradingEngine.current.strategyOpenStage.exitType.value = exitType
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'Manage Stage': {
|
||||
tradingEngine.current.strategy.manageStageStatus.value = status
|
||||
tradingEngine.current.strategyManageStage.status.value = status
|
||||
break
|
||||
}
|
||||
case 'Close Stage': {
|
||||
tradingEngine.current.strategy.closeStageStatus.value = status
|
||||
tradingEngine.current.strategyCloseStage.status.value = status
|
||||
if (exitType !== undefined) {
|
||||
tradingEngine.current.strategyCloseStage.exitType.value = exitType
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,27 +143,27 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
|
||||
stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
|
||||
executionNode = stageNode.openExecution
|
||||
resetExecution(executionNode)
|
||||
resetExecution(executionNode, tradingEngine.current.strategyOpenStage.status.value)
|
||||
|
||||
stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].closeStage
|
||||
executionNode = stageNode.closeExecution
|
||||
resetExecution(executionNode)
|
||||
resetExecution(executionNode, tradingEngine.current.strategyCloseStage.status.value)
|
||||
|
||||
function resetExecution(executionNode) {
|
||||
function resetExecution(executionNode, stageStatus) {
|
||||
|
||||
resetExecutionAlgorithms(executionNode)
|
||||
|
||||
function resetExecutionAlgorithms(executionNode) {
|
||||
for (let i = 0; i < executionNode.executionAlgorithms.length; i++) {
|
||||
let executionAlgorithm = executionNode.executionAlgorithms[i]
|
||||
resetOrders(executionAlgorithm.marketBuyOrders, executionAlgorithm, executionNode)
|
||||
resetOrders(executionAlgorithm.marketSellOrders, executionAlgorithm, executionNode)
|
||||
resetOrders(executionAlgorithm.limitBuyOrders, executionAlgorithm, executionNode)
|
||||
resetOrders(executionAlgorithm.limitSellOrders, executionAlgorithm, executionNode)
|
||||
resetOrders(executionAlgorithm.marketBuyOrders)
|
||||
resetOrders(executionAlgorithm.marketSellOrders)
|
||||
resetOrders(executionAlgorithm.limitBuyOrders)
|
||||
resetOrders(executionAlgorithm.limitSellOrders)
|
||||
}
|
||||
}
|
||||
|
||||
function resetOrders(orders, executionAlgorithm, executionNode) {
|
||||
function resetOrders(orders) {
|
||||
for (let i = 0; i < orders.length; i++) {
|
||||
let tradingSystemOrder = orders[i]
|
||||
if (tradingSystemOrder.referenceParent === undefined) { continue }
|
||||
@@ -172,6 +172,14 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
if (tradingEngineOrder.status.value === 'Closed') {
|
||||
/* We reset the order data structure inside the Trading Engine to its initial value */
|
||||
tradingEngineOrder.initialize(tradingEngineOrder)
|
||||
if (tradingSystemOrder.config.spawnMultipleOrders !== true) {
|
||||
/*
|
||||
We close the lock so as to prevent this data structure to be used again during this same stage execution.
|
||||
*/
|
||||
if (stageStatus === 'Open') {
|
||||
tradingEngineOrder.lock.value = 'Closed'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -205,7 +213,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
}
|
||||
|
||||
/* Here we check if there is a formula to be evaluated */
|
||||
if (node.type === 'Formula' && evaluating === 'Formulas') {
|
||||
if ((node.type === 'Formula' || node.type === 'Announcement Formula') && evaluating === 'Formulas') {
|
||||
if (node.code !== undefined) {
|
||||
/* We will eval this formula */
|
||||
if (isDescendent === true) {
|
||||
@@ -322,13 +330,18 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
}
|
||||
}
|
||||
|
||||
tradingSystem.formulas.set(node.id, value)
|
||||
|
||||
if (error !== undefined) {
|
||||
tradingSystem.errors.push([node.id, error])
|
||||
return
|
||||
}
|
||||
if (value !== undefined) {
|
||||
if (node.type === 'Formula' && isNaN(value)) {
|
||||
tradingSystem.errors.push([node.id, 'Formula needs to return a number.'])
|
||||
return
|
||||
}
|
||||
|
||||
tradingSystem.values.push([node.id, value])
|
||||
tradingSystem.formulas.set(node.id, value)
|
||||
}
|
||||
|
||||
logger.write(MODULE_NAME, '[INFO] evalFormula -> value = ' + value)
|
||||
@@ -409,7 +422,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
}
|
||||
|
||||
function checkTriggerOff() {
|
||||
if (tradingEngine.current.strategy.triggerStageStatus.value === 'Open') {
|
||||
if (tradingEngine.current.strategyTriggerStage.status.value === 'Open') {
|
||||
|
||||
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
|
||||
let triggerStage = strategy.triggerStage
|
||||
@@ -446,7 +459,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
|
||||
function checkTakePosition() {
|
||||
if (
|
||||
tradingEngine.current.strategy.triggerStageStatus.value === 'Open'
|
||||
tradingEngine.current.strategyTriggerStage.status.value === 'Open'
|
||||
) {
|
||||
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
|
||||
let triggerStage = strategy.triggerStage
|
||||
@@ -471,12 +484,6 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
tradingSystem.highlights.push(triggerStage.takePosition.id)
|
||||
tradingSystem.highlights.push(triggerStage.id)
|
||||
|
||||
/* Updating Episode Counters */
|
||||
tradingEngine.episode.episodeCounters.positions.value++
|
||||
|
||||
/* Inicializing this counter */
|
||||
tradingEngine.current.distanceToEvent.takePosition.value = 1
|
||||
|
||||
tradingPositionModule.openPosition(situation.name)
|
||||
|
||||
announcementsModule.makeAnnoucements(triggerStage.takePosition)
|
||||
@@ -503,7 +510,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
|
||||
async function openStage() {
|
||||
/* Abort Open Stage Check */
|
||||
if (tradingEngine.current.strategy.openStageStatus.value === 'Open' && tradingEngine.current.strategy.closeStageStatus.value === 'Open') {
|
||||
if (tradingEngine.current.strategyOpenStage.status.value === 'Open' && tradingEngine.current.strategyCloseStage.status.value === 'Open') {
|
||||
/*
|
||||
if the Close stage is opened while the open stage is still open that means that
|
||||
we need to stop placing orders, check what happened to the orders already placed,
|
||||
@@ -513,7 +520,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
}
|
||||
|
||||
/* Opening Status Procedure */
|
||||
if (tradingEngine.current.strategy.openStageStatus.value === 'Opening') {
|
||||
if (tradingEngine.current.strategyOpenStage.status.value === 'Opening') {
|
||||
|
||||
/* This procedure is intended to run only once */
|
||||
let stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
|
||||
@@ -525,28 +532,33 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
evalConditions(stageNode, 'Initial Definition')
|
||||
evalFormulas(stageNode, 'Initial Definition')
|
||||
|
||||
getReadyToTakePosition()
|
||||
|
||||
calculateTakeProfit()
|
||||
calculateStopLoss()
|
||||
|
||||
/* Remember the balance we had before taking the position to later calculate profit or loss */
|
||||
tradingEngine.previous.balance.baseAsset.value = tradingEngine.current.balance.baseAsset.value
|
||||
tradingEngine.previous.balance.quotedAsset.value = tradingEngine.current.balance.quotedAsset.value
|
||||
|
||||
/* Check Execution in opening stage node */
|
||||
/* Position size and rate */
|
||||
tradingPositionModule.initializeSizeAndRate()
|
||||
|
||||
/* Check Execution at open stage node */
|
||||
evalConditions(stageNode, 'Open Execution')
|
||||
evalFormulas(stageNode, 'Open Execution')
|
||||
|
||||
await tradingExecutionModule.checkExecution(executionNode, true, false, tradingEngine.current.position.size, tradingEngine.current.position.openStageOrdersSize, tradingEngine.current.position.openStageFilledSize)
|
||||
await tradingExecutionModule.checkExecution(
|
||||
executionNode,
|
||||
true,
|
||||
false,
|
||||
tradingEngine.current.position.positionBaseAsset.size, // Stage Size Limit
|
||||
tradingEngine.current.position.positionQuotedAsset.size, // Stage Size Limit
|
||||
tradingEngine.current.position.strategyOpenStage
|
||||
)
|
||||
|
||||
/* From here on, the state is officially Open */
|
||||
/* From here on, the state is officialy Open */
|
||||
tradingStrategyModule.updateStageStatus('Open Stage', 'Open')
|
||||
return
|
||||
}
|
||||
|
||||
/* Open Status Procedure */
|
||||
if (tradingEngine.current.strategy.openStageStatus.value === 'Open') {
|
||||
if (tradingEngine.current.strategyOpenStage.status.value === 'Open') {
|
||||
/*
|
||||
While the Open Stage is Open, we do our regular stuff: place orders and check
|
||||
what happened to the orders already placed.
|
||||
@@ -558,20 +570,35 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
evalConditions(stageNode, 'Open Execution')
|
||||
evalFormulas(stageNode, 'Open Execution')
|
||||
|
||||
await tradingExecutionModule.checkExecution(executionNode, false, false, tradingEngine.current.position.size, tradingEngine.current.position.openStageOrdersSize, tradingEngine.current.position.openStageFilledSize)
|
||||
|
||||
await tradingExecutionModule.checkExecution(
|
||||
executionNode,
|
||||
false,
|
||||
false,
|
||||
tradingEngine.current.position.positionBaseAsset.size, // Stage Size Limit
|
||||
tradingEngine.current.position.positionQuotedAsset.size, // Stage Size Limit
|
||||
tradingEngine.current.position.strategyOpenStage
|
||||
)
|
||||
/*
|
||||
The Open is finished when the fillSize reaches the Position Size.
|
||||
The Open is finished when the fillSize + feesPaid reaches the Position Size.
|
||||
This can happens at any time when we update the filledSize value when we see
|
||||
at the exchange that orders were filled.
|
||||
*/
|
||||
if (tradingEngine.current.position.openStageFilledSize.value === tradingEngine.current.position.size.value) {
|
||||
tradingStrategyModule.updateStageStatus('Open Stage', 'Closed')
|
||||
if (
|
||||
tradingEngine.current.strategyOpenStage.stageBaseAsset.filledSize.value +
|
||||
tradingEngine.current.strategyOpenStage.stageBaseAsset.feesPaid.value >=
|
||||
tradingEngine.current.position.positionBaseAsset.size.value * 0.999) {
|
||||
tradingStrategyModule.updateStageStatus('Open Stage', 'Closed', 'Position Size Filled')
|
||||
} else {
|
||||
/* Check the Close Stage Event */
|
||||
evalConditions(stageNode, 'Close Stage Event')
|
||||
if (checkStopStageEvent(stageNode) === true) {
|
||||
tradingStrategyModule.updateStageStatus('Open Stage', 'Closing', 'Close Stage Event')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Closing Status Procedure */
|
||||
if (tradingEngine.current.strategy.openStageStatus.value === 'Closing') {
|
||||
if (tradingEngine.current.strategyOpenStage.status.value === 'Closing') {
|
||||
/*
|
||||
During the closing stage status, we do not place new orders, just check
|
||||
if the ones placed were filled, and cancel the ones not filled.
|
||||
@@ -586,71 +613,41 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
evalConditions(stageNode, 'Open Execution')
|
||||
evalFormulas(stageNode, 'Open Execution')
|
||||
|
||||
await tradingExecutionModule.checkExecution(executionNode, false, true, tradingEngine.current.position.size, tradingEngine.current.position.openStageOrdersSize, tradingEngine.current.position.openStageFilledSize)
|
||||
await tradingExecutionModule.checkExecution(
|
||||
executionNode,
|
||||
false,
|
||||
true,
|
||||
tradingEngine.current.position.positionBaseAsset.size, // Stage Size Limit
|
||||
tradingEngine.current.position.positionQuotedAsset.size, // Stage Size Limit
|
||||
tradingEngine.current.position.strategyOpenStage
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
The Closing is finished when the fillSize reaches the ordersSize.
|
||||
The Closing is finished when the fillSize + feesPaid reaches the ordersSize.
|
||||
This can happens either because we update the filledSize value when we see
|
||||
at the exchange that orders were filled, or we reduce the ordersSize when
|
||||
we cancel not yet filled orders.
|
||||
*/
|
||||
if (tradingEngine.current.position.openStageFilledSize.value === tradingEngine.current.position.openStageOrdersSize.value) {
|
||||
if (
|
||||
tradingEngine.current.strategyOpenStage.stageBaseAsset.filledSize.value +
|
||||
tradingEngine.current.strategyOpenStage.stageBaseAsset.feesPaid.value >=
|
||||
tradingEngine.current.position.positionBaseAsset.size.value * 0.999) {
|
||||
tradingStrategyModule.updateStageStatus('Open Stage', 'Closed')
|
||||
}
|
||||
}
|
||||
|
||||
function getReadyToTakePosition() {
|
||||
|
||||
/* Position size and rate */
|
||||
tradingPositionModule.updateSizeAndRate(getPositionSize(), getPositionRate())
|
||||
|
||||
function getPositionSize() {
|
||||
let balance
|
||||
if (bot.sessionAndMarketBaseAssetsAreEqual) {
|
||||
balance = tradingEngine.current.balance.baseAsset.value
|
||||
} else {
|
||||
balance = tradingEngine.current.balance.quotedAsset.value
|
||||
}
|
||||
const DEFAULT_VALUE = balance
|
||||
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
|
||||
|
||||
if (strategy.openStage === undefined) return DEFAULT_VALUE
|
||||
if (strategy.openStage.initialDefinition === undefined) return DEFAULT_VALUE
|
||||
if (strategy.openStage.initialDefinition.positionSize === undefined) return DEFAULT_VALUE
|
||||
if (strategy.openStage.initialDefinition.positionSize.formula === undefined) return DEFAULT_VALUE
|
||||
|
||||
let value = tradingSystem.formulas.get(strategy.openStage.initialDefinition.positionSize.formula.id)
|
||||
if (value === undefined) return DEFAULT_VALUE
|
||||
return value
|
||||
}
|
||||
|
||||
function getPositionRate() {
|
||||
const DEFAULT_VALUE = tradingEngine.current.candle.close.value
|
||||
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
|
||||
|
||||
if (strategy.openStage === undefined) return DEFAULT_VALUE
|
||||
if (strategy.openStage.initialDefinition === undefined) return DEFAULT_VALUE
|
||||
if (strategy.openStage.initialDefinition.positionRate === undefined) return DEFAULT_VALUE
|
||||
if (strategy.openStage.initialDefinition.positionRate.formula === undefined) return DEFAULT_VALUE
|
||||
|
||||
let value = tradingSystem.formulas.get(strategy.openStage.initialDefinition.positionRate.formula.id)
|
||||
if (value === undefined) return DEFAULT_VALUE
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function manageStage() {
|
||||
/* Opening Status Procedure */
|
||||
if (tradingEngine.current.strategy.manageStageStatus.value === 'Opening') {
|
||||
if (tradingEngine.current.strategyManageStage.status.value === 'Opening') {
|
||||
/* We jump the management at the loop cycle where the position is being taken. */
|
||||
tradingStrategyModule.updateStageStatus('Manage Stage', 'Open')
|
||||
return
|
||||
}
|
||||
|
||||
/* Open Status Procedure */
|
||||
if (tradingEngine.current.strategy.manageStageStatus.value === 'Open') {
|
||||
if (tradingEngine.current.strategyManageStage.status.value === 'Open') {
|
||||
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
|
||||
let manageStage = strategy.manageStage
|
||||
evalConditions(manageStage, 'Manage Stage')
|
||||
@@ -936,7 +933,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
|
||||
async function closeStage() {
|
||||
/* Opening Status Procedure */
|
||||
if (tradingEngine.current.strategy.closeStageStatus.value === 'Opening') {
|
||||
if (tradingEngine.current.strategyCloseStage.status.value === 'Opening') {
|
||||
/*
|
||||
This will happen only once, as soon as the Take Profit or Stop was hit.
|
||||
We wil not be placing orders at this time because we do not know
|
||||
@@ -948,7 +945,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
}
|
||||
|
||||
/* Open Status Procedure */
|
||||
if (tradingEngine.current.strategy.closeStageStatus.value === 'Open') {
|
||||
if (tradingEngine.current.strategyCloseStage.status.value === 'Open') {
|
||||
/*
|
||||
This will happen as long as the Close Stage is Open.
|
||||
*/
|
||||
@@ -958,23 +955,40 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
evalConditions(stageNode, 'Close Execution')
|
||||
evalFormulas(stageNode, 'Close Execution')
|
||||
|
||||
await tradingExecutionModule.checkExecution(executionNode, false, false, tradingEngine.current.position.openStageFilledSize, tradingEngine.current.position.closeStageOrdersSize, tradingEngine.current.position.closeStageFilledSize)
|
||||
await tradingExecutionModule.checkExecution(
|
||||
executionNode,
|
||||
false,
|
||||
false,
|
||||
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled, // Stage Size Limit
|
||||
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizeFilled, // Stage Size Limit
|
||||
tradingEngine.current.position.strategyCloseStage
|
||||
)
|
||||
|
||||
/* Close the Stage Validation */
|
||||
if (tradingEngine.current.position.closeStageFilledSize.value === tradingEngine.current.position.openStageFilledSize.value) {
|
||||
/*
|
||||
The Close Stage is closed when the fillSize reaches the filledSize of the Open Stage.
|
||||
*/
|
||||
tradingStrategyModule.updateStageStatus('Close Stage', 'Closed')
|
||||
/*
|
||||
The Close Stage is finished when the fillSize + feesPaid reaches the Open Fill Size.
|
||||
This can happens at any time when we update the filledSize value when we see
|
||||
at the exchange that orders were filled.
|
||||
*/
|
||||
if (
|
||||
tradingEngine.current.strategyCloseStage.stageBaseAsset.filledSize.value +
|
||||
tradingEngine.current.strategyCloseStage.stageBaseAsset.feesPaid.value >=
|
||||
tradingEngine.current.strategyOpenStage.stageBaseAsset.filledSize.value * 0.999) {
|
||||
tradingStrategyModule.updateStageStatus('Close Stage', 'Closed', 'Open Stage fillSize Filled')
|
||||
} else {
|
||||
/* Check the Close Stage Event */
|
||||
evalConditions(stageNode, 'Close Stage Event')
|
||||
if (checkStopStageEvent(stageNode) === true) {
|
||||
tradingStrategyModule.updateStageStatus('Close Stage', 'Closing', 'Close Stage Event')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Exit Position Validation */
|
||||
if (
|
||||
tradingEngine.current.strategy.triggerStageStatus.value === 'Closed' &&
|
||||
tradingEngine.current.strategy.openStageStatus.value === 'Closed' &&
|
||||
tradingEngine.current.strategy.manageStageStatus.value === 'Closed' &&
|
||||
tradingEngine.current.strategy.closeStageStatus.value === 'Closed'
|
||||
tradingEngine.current.strategyTriggerStage.status.value === 'Closed' &&
|
||||
tradingEngine.current.strategyOpenStage.status.value === 'Closed' &&
|
||||
tradingEngine.current.strategyManageStage.status.value === 'Closed' &&
|
||||
tradingEngine.current.strategyCloseStage.status.value === 'Closed'
|
||||
) {
|
||||
|
||||
/* Exiting Everything now. */
|
||||
@@ -1100,6 +1114,33 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
}
|
||||
}
|
||||
|
||||
function checkStopStageEvent(stage) {
|
||||
|
||||
/* Check the Close Stage Event. */
|
||||
let stopStageEvent = stage.stopStageEvent
|
||||
if (stopStageEvent !== undefined) {
|
||||
for (let k = 0; k < stopStageEvent.situations.length; k++) {
|
||||
let situation = stopStageEvent.situations[k]
|
||||
let passed
|
||||
if (situation.conditions.length > 0) {
|
||||
passed = true
|
||||
}
|
||||
|
||||
passed = tradingSystem.checkConditions(situation, passed)
|
||||
|
||||
tradingSystem.values.push([situation.id, passed])
|
||||
if (passed) {
|
||||
tradingSystem.highlights.push(situation.id)
|
||||
tradingSystem.highlights.push(stopStageEvent.id)
|
||||
tradingSystem.highlights.push(stage.id)
|
||||
|
||||
announcementsModule.makeAnnoucements(stopStageEvent)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isItInside(elementWithTimestamp, elementWithBeginEnd) {
|
||||
/*
|
||||
The function is to allow in Conditions and Formulas to easily know when an element with timestamp (like the ones of single files) are inside the time range
|
||||
|
||||