MOre sutff
This commit is contained in:
1 parent
6fb5bdb627
commit
89d6edc343
3 files changed
+350
-215
No files matched your search
@@ -168,12 +168,13 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
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
|
||||
@@ -184,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')
|
||||
}
|
||||
}
|
||||
@@ -199,22 +209,23 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
}
|
||||
}
|
||||
|
||||
async function openOrder(executionAlgorithm, tradingSystemOrder, tradingEngineOrder, situationName) {
|
||||
async function tryToOpenOrder(executionAlgorithm, tradingSystemOrder, tradingEngineOrder, situationName) {
|
||||
|
||||
calculateOrderRate()
|
||||
calculateOrderSize()
|
||||
|
||||
/* Check Size: We are not going to create Orders which size is equal or less to zero. */
|
||||
if (traingEngineOrderAsset.size.value <= 0) { return }
|
||||
|
||||
calculateOrderRate()
|
||||
|
||||
/* Place Order at the Exchange */
|
||||
let result = await createOrderAtExchange(tradingSystemOrder, tradingEngineOrder)
|
||||
if (result !== true) { return }
|
||||
|
||||
/* Update Stage Counters */
|
||||
tradingEngineStageAsset.value = tradingEngineStageAsset.value + tradingEngineOrder.size.value
|
||||
tradingEngineStageAsset.value = global.PRECISE(tradingEngineStageAsset.value, 10)
|
||||
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++
|
||||
@@ -232,6 +243,29 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
tradingEngineOrder.algorithmName.value = executionAlgorithm.name
|
||||
tradingEngineOrder.situationName.value = situationName
|
||||
|
||||
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)
|
||||
|
||||
if (tradingEngineOrder.rate.value === undefined) {
|
||||
const errorText = 'Rate cannot be undefined. Fix this please.'
|
||||
tradingSystem.errors.push([tradingSystemOrder.positionRate.formula.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function calculateOrderSize() {
|
||||
/*
|
||||
If the position size was defined in Base Asset, then
|
||||
@@ -290,60 +324,50 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
traingEngineOrderAsset.size.value = global.PRECISE(traingEngineOrderAsset.size.value, 10)
|
||||
|
||||
/* Check against the Stage Size Limit */
|
||||
if (tradingEngineStageAsset.size.value + traingEngineOrderAsset.size.value > stageSizeLimit.value) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if (tradingEngineOrder.rate.value === undefined) {
|
||||
const errorText = 'Rate cannot be undefined. Fix this please.'
|
||||
tradingSystem.errors.push([tradingSystemOrder.positionRate.formula.id, errorText])
|
||||
throw (errorText)
|
||||
}
|
||||
|
||||
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)
|
||||
/* 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) {
|
||||
async function createOrderAtExchange(tradingSystemOrder, tradingEngineOrder) {
|
||||
|
||||
/* Filter by Session Type */
|
||||
switch (bot.SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
/* 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
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,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
|
||||
@@ -379,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') {
|
||||
@@ -589,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
|
||||
@@ -724,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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,11 +143,11 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
|
||||
stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
|
||||
executionNode = stageNode.openExecution
|
||||
resetExecution(executionNode, tradingEngine.current.strategy.openStageStatus.value)
|
||||
resetExecution(executionNode, tradingEngine.current.strategyOpenStage.status.value)
|
||||
|
||||
stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].closeStage
|
||||
executionNode = stageNode.closeExecution
|
||||
resetExecution(executionNode, tradingEngine.current.strategy.closeStageStatus.value)
|
||||
resetExecution(executionNode, tradingEngine.current.strategyCloseStage.status.value)
|
||||
|
||||
function resetExecution(executionNode, stageStatus) {
|
||||
|
||||
@@ -422,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
|
||||
@@ -459,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
|
||||
@@ -510,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,
|
||||
@@ -520,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
|
||||
@@ -558,7 +558,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
}
|
||||
|
||||
/* 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.
|
||||
@@ -579,23 +579,26 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
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')
|
||||
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.
|
||||
@@ -621,33 +624,30 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
}
|
||||
|
||||
/*
|
||||
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')
|
||||
} else {
|
||||
/* Check the Close Stage Event */
|
||||
evalConditions(stageNode, 'Close Stage Event')
|
||||
if (checkStopStageEvent(stageNode) === true) {
|
||||
tradingStrategyModule.updateStageStatus('Open Stage', 'Closed')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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')
|
||||
@@ -933,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
|
||||
@@ -945,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.
|
||||
*/
|
||||
@@ -964,19 +964,31 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
tradingEngine.current.position.strategyCloseStage
|
||||
)
|
||||
|
||||
/* Check the Close Stage Event */
|
||||
evalConditions(stageNode, 'Close Stage Event')
|
||||
if (checkStopStageEvent(stageNode) === true) {
|
||||
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. */
|
||||
|
||||
Reference in new issue
Block a user