func verifyOrderWithinLimits(f *fill.Fill, limitReducedAmount decimal.Decimal, cs *Settings) error {
	if f == nil {
		return common.ErrNilEvent
	}
	if cs == nil {
		return errNilCurrencySettings
	}
	isBeyondLimit := false
	var minMax config.MinMax
	var direction gctorder.Side
	switch f.GetDirection() {
	case gctorder.Buy:
		minMax = cs.BuySide
		direction = common.CouldNotBuy
	case gctorder.Sell:
		minMax = cs.SellSide
		direction = common.CouldNotSell
	default:
		direction = f.GetDirection()
		f.SetDirection(common.DoNothing)
		return fmt.Errorf("%w: %v", errInvalidDirection, direction)
	}
	var minOrMax, belowExceed string
	var size decimal.Decimal
	if limitReducedAmount.LessThan(minMax.MinimumSize) && minMax.MinimumSize.GreaterThan(decimal.Zero) {
		isBeyondLimit = true
		belowExceed = "below"
		minOrMax = "minimum"
		size = minMax.MinimumSize
	}
	if limitReducedAmount.GreaterThan(minMax.MaximumSize) && minMax.MaximumSize.GreaterThan(decimal.Zero) {
		isBeyondLimit = true
		belowExceed = "exceeded"
		minOrMax = "maximum"
		size = minMax.MaximumSize
	}
	if isBeyondLimit {
		f.SetDirection(direction)
		e := fmt.Sprintf("Order size %v %s %s size %v", limitReducedAmount, belowExceed, minOrMax, size)
		f.AppendReason(e)
		return fmt.Errorf("%w %v", errExceededPortfolioLimit, e)
	}
	return nil
}
verifyOrderWithinLimits conforms the amount to fall into the minimum size and maximum size limit after reduced
package exchange
import (
	"context"
	"fmt"
	"github.com/gofrs/uuid"
	"github.com/shopspring/decimal"
	"github.com/thrasher-corp/gocryptotrader/backtester/common"
	"github.com/thrasher-corp/gocryptotrader/backtester/config"
	"github.com/thrasher-corp/gocryptotrader/backtester/data"
	"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/exchange/slippage"
	"github.com/thrasher-corp/gocryptotrader/backtester/eventtypes/event"
	"github.com/thrasher-corp/gocryptotrader/backtester/eventtypes/fill"
	"github.com/thrasher-corp/gocryptotrader/backtester/eventtypes/order"
	"github.com/thrasher-corp/gocryptotrader/backtester/funding"
	"github.com/thrasher-corp/gocryptotrader/currency"
	"github.com/thrasher-corp/gocryptotrader/engine"
	"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
	gctorder "github.com/thrasher-corp/gocryptotrader/exchanges/order"
	"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
)
func (e *Exchange) Reset() {
	*e = Exchange{}
}
func (e *Exchange) ExecuteOrder(o order.Event, data data.Handler, bot *engine.Engine, funds funding.IPairReleaser) (*fill.Fill, error) {
	f := &fill.Fill{
		Base: event.Base{
			Offset:       o.GetOffset(),
			Exchange:     o.GetExchange(),
			Time:         o.GetTime(),
			CurrencyPair: o.Pair(),
			AssetType:    o.GetAssetType(),
			Interval:     o.GetInterval(),
			Reason:       o.GetReason(),
		},
		Direction:  o.GetDirection(),
		Amount:     o.GetAmount(),
		ClosePrice: data.Latest().ClosePrice(),
	}
	eventFunds := o.GetAllocatedFunds()
	cs, err := e.GetCurrencySettings(o.GetExchange(), o.GetAssetType(), o.Pair())
	if err != nil {
		return f, err
	}
	f.ExchangeFee = cs.ExchangeFee  
	f.Direction = o.GetDirection()
	if o.GetDirection() != gctorder.Buy && o.GetDirection() != gctorder.Sell {
		return f, nil
	}
	highStr := data.StreamHigh()
	high := highStr[len(highStr)-1]
	lowStr := data.StreamLow()
	low := lowStr[len(lowStr)-1]
	volStr := data.StreamVol()
	volume := volStr[len(volStr)-1]
	var adjustedPrice, amount decimal.Decimal
	if cs.UseRealOrders {
		var ob *orderbook.Base
		ob, err = orderbook.Get(f.Exchange, f.CurrencyPair, f.AssetType)
		if err != nil {
			return f, err
		}
		adjustedPrice, amount = slippage.CalculateSlippageByOrderbook(ob, o.GetDirection(), eventFunds, f.ExchangeFee)
		f.Slippage = adjustedPrice.Sub(f.ClosePrice).Div(f.ClosePrice).Mul(decimal.NewFromInt(100))
	} else {
		adjustedPrice, amount, err = e.sizeOfflineOrder(high, low, volume, &cs, f)
		if err != nil {
			switch f.GetDirection() {
			case gctorder.Buy:
				f.SetDirection(common.CouldNotBuy)
			case gctorder.Sell:
				f.SetDirection(common.CouldNotSell)
			default:
				f.SetDirection(common.DoNothing)
			}
			f.AppendReason(err.Error())
			return f, err
		}
	}
	portfolioLimitedAmount := reduceAmountToFitPortfolioLimit(adjustedPrice, amount, eventFunds, f.GetDirection())
	if !portfolioLimitedAmount.Equal(amount) {
		f.AppendReason(fmt.Sprintf("Order size shrunk from %v to %v to remain within portfolio limits", amount, portfolioLimitedAmount))
	}
	limitReducedAmount := portfolioLimitedAmount
	if cs.CanUseExchangeLimits {
		limitReducedAmount = cs.Limits.ConformToDecimalAmount(portfolioLimitedAmount)
		if !limitReducedAmount.Equal(portfolioLimitedAmount) {
			f.AppendReason(fmt.Sprintf("Order size shrunk from %v to %v to remain within exchange step amount limits",
				portfolioLimitedAmount,
				limitReducedAmount))
		}
	}
	err = verifyOrderWithinLimits(f, limitReducedAmount, &cs)
	if err != nil {
		return f, err
	}
	f.ExchangeFee = calculateExchangeFee(adjustedPrice, limitReducedAmount, cs.ExchangeFee)
	orderID, err := e.placeOrder(context.TODO(), adjustedPrice, limitReducedAmount, cs.UseRealOrders, cs.CanUseExchangeLimits, f, bot)
	if err != nil {
		fundErr := funds.Release(eventFunds, eventFunds, f.GetDirection())
		if fundErr != nil {
			f.AppendReason(fundErr.Error())
		}
		if f.GetDirection() == gctorder.Buy {
			f.SetDirection(common.CouldNotBuy)
		} else if f.GetDirection() == gctorder.Sell {
			f.SetDirection(common.CouldNotSell)
		}
		return f, err
	}
	switch f.GetDirection() {
	case gctorder.Buy:
		err = funds.Release(eventFunds, eventFunds.Sub(limitReducedAmount.Mul(adjustedPrice)), f.GetDirection())
		if err != nil {
			return f, err
		}
		funds.IncreaseAvailable(limitReducedAmount, f.GetDirection())
	case gctorder.Sell:
		err = funds.Release(eventFunds, eventFunds.Sub(limitReducedAmount), f.GetDirection())
		if err != nil {
			return f, err
		}
		funds.IncreaseAvailable(limitReducedAmount.Mul(adjustedPrice), f.GetDirection())
	}
	ords, _ := bot.OrderManager.GetOrdersSnapshot("")
	for i := range ords {
		if ords[i].ID != orderID {
			continue
		}
		ords[i].Date = o.GetTime()
		ords[i].LastUpdated = o.GetTime()
		ords[i].CloseTime = o.GetTime()
		f.Order = &ords[i]
		f.PurchasePrice = decimal.NewFromFloat(ords[i].Price)
		f.Total = f.PurchasePrice.Mul(limitReducedAmount).Add(f.ExchangeFee)
	}
	if f.Order == nil {
		return nil, fmt.Errorf("placed order %v not found in order manager", orderID)
	}
	return f, nil
}