Open order Implemented

This commit is contained in:
Luis Fernando Molina committed 2020-08-01 15:29:45 +02:00
1 parent 68febdcf74
commit 6fb5bdb627
4 files changed
+271 -106

No files matched your search

+11 -1
View File
@@ -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': {
+157 -34
View File
@@ -47,18 +47,45 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
executionNode,
stageIsOpening,
stageIsClosing,
stageSizeLimit,
stageOrdersSizeInBaseAsset,
stageFilledSizeInBaseAsset,
stageOrdersSizeInQuotedAsset,
stageFilledSizeInQuotedAsset
stageSizeLimitInBaseAsset,
stageSizeLimitInQuotedAsset,
tradingEngineStage
) {
/* Enforcing Precision Limit */
stageOrdersSizeInBaseAsset.value = global.PRECISE(stageOrdersSizeInBaseAsset.value, 10)
stageOrdersSizeInBaseAsset.value = global.PRECISE(stageOrdersSizeInBaseAsset.value, 10)
stageOrdersSizeInQuotedAsset.value = global.PRECISE(stageOrdersSizeInQuotedAsset.value, 10)
stageFilledSizeInQuotedAsset.value = global.PRECISE(stageFilledSizeInQuotedAsset.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)
@@ -90,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 }
@@ -100,9 +126,33 @@ 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': {
{
/* 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
@@ -114,7 +164,6 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
}
}
/* Check if we need to Create this Order */
if (stageIsClosing === true) { continue }
let situationName = checkOrderEvent(tradingSystemOrder.createOrderEvent, tradingSystemOrder, executionAlgorithm, executionNode)
if (situationName !== undefined) {
@@ -151,32 +200,22 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
}
async function openOrder(executionAlgorithm, tradingSystemOrder, tradingEngineOrder, situationName) {
/* Order Size Calculation */
let positionSize = tradingSystem.formulas.get(executionAlgorithm.positionSize.formula.id)
if (positionSize === undefined) { return }
tradingEngineOrder.size.value = positionSize * 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)
}
/* Check Order Size */
if (tradingEngineOrder.size.value <= 0) { return }
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 }
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)
/* Updating Episode Counters */
tradingEngine.episode.episodeCounters.orders.value++
@@ -193,9 +232,93 @@ 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 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)
}
}
/* 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)
}
}
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)
}
}
}
}
async function createOrderAtExchange(tradingSystemOrder, tradingEngineOrder) {
+86 -5
View File
@@ -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() {
+17 -66
View File
@@ -484,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)
@@ -538,16 +532,14 @@ 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')
@@ -555,12 +547,12 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
executionNode,
true,
false,
tradingEngine.current.position.size,
tradingEngine.current.position.openStageOrdersSize,
tradingEngine.current.position.openStageFilledSize
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
}
@@ -582,9 +574,9 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
executionNode,
false,
false,
tradingEngine.current.position.size,
tradingEngine.current.position.openStageOrdersSize,
tradingEngine.current.position.openStageFilledSize
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.
@@ -622,9 +614,9 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
executionNode,
false,
true,
tradingEngine.current.position.size,
tradingEngine.current.position.openStageOrdersSize,
tradingEngine.current.position.openStageFilledSize
tradingEngine.current.position.positionBaseAsset.size, // Stage Size Limit
tradingEngine.current.position.positionQuotedAsset.size, // Stage Size Limit
tradingEngine.current.position.strategyOpenStage
)
}
@@ -644,46 +636,6 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
}
}
}
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() {
@@ -1003,14 +955,13 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
evalConditions(stageNode, 'Close Execution')
evalFormulas(stageNode, 'Close Execution')
let stageLimitSize = tradingEngine.current.balance.quotedAsset.value / tradingEngine.current.candle.close.value
await tradingExecutionModule.checkExecution(
executionNode,
false,
false,
stageLimitSize,
tradingEngine.current.position.closeStageOrdersSize,
tradingEngine.current.position.closeStageFilledSize
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled, // Stage Size Limit
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizeFilled, // Stage Size Limit
tradingEngine.current.position.strategyCloseStage
)
/* Check the Close Stage Event */