# twap/events/self_interval_tick.js

    'use strict'

    const _isEmpty = require('lodash/isEmpty')
    const _isFinite = require('lodash/isFinite')
    const hasTradeTarget = require('../util/has_trade_target')
    const hasOBTarget = require('../util/has_ob_target')
    const generateOrder = require('../util/generate_order')
    const getOBPrice = require('../util/get_ob_price')
    const getTradePrice = require('../util/get_trade_price')
    const isTargetMet = require('../util/is_target_met')

    /**
     * Submits the next slice order if the price condition/target is met.
     *
     * @memberOf module:TWAP
     * @listens module:TWAP~selfIntervalTick
     *
     * @param {AOInstance} instance - AO instance
     * @returns {Promise} p - resolves on completion
     */
    const onSelfIntervalTick = async (instance = {}) => {
      const { state = {}, h = {} } = instance
      const { orders = {}, args = {}, gid } = state
      const { emit, debug, timeout } = h
      const {
        priceTarget, tradeBeyondEnd, cancelDelay, submitDelay, priceDelta,
        orderType, sliceAmount, amount
      } = args

      debug('tick')

      if (!tradeBeyondEnd && !_isEmpty(orders)) {
        await emit('exec:order:cancel:all', gid, orders, cancelDelay)
      }

      // Ensure that the next order would not push us over the total amount
      if (tradeBeyondEnd) {
        let openAmount = 0

        Object.values(orders).forEach(o => { openAmount += o.amount })

        if (
          (amount > 0 && (openAmount + sliceAmount > amount)) ||
          (amount < 0 && (openAmount + sliceAmount < amount))
        ) {
          debug('next tick would exceed total order amount, refusing')
          return
        }
      }

      if (submitDelay) {
        await timeout(submitDelay)
      }

      let orderPrice

      if (!/MARKET/.test(orderType)) {
        if (hasTradeTarget(args)) {
          orderPrice = getTradePrice(state)
        } else if (hasOBTarget(args)) {
          orderPrice = getOBPrice(state)
        }

        if (!_isFinite(orderPrice)) {
          debug('price data unavailable, awaiting next tick')
          return
        }

        if (_isFinite(priceTarget)) {
          const targetMet = isTargetMet(args, orderPrice)

          if (!targetMet) {
            debug(
              'target not met | price %f (target %s delta %f)',
              orderPrice, priceTarget, priceDelta
            )

            return
          }
        }

        debug('target met | price %f (target %s)', orderPrice, priceTarget)
      }

      const order = generateOrder(state, orderPrice)
      if (order) {
        await emit('exec:order:submit:all', gid, [order], 0)
      }
    }

    module.exports = onSelfIntervalTick