decred.org/dcrdex@v1.0.3/client/mm/config.go (about)

     1  package mm
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strconv"
     7  )
     8  
     9  // MarketMakingConfig is the overall configuration of the market maker.
    10  type MarketMakingConfig struct {
    11  	BotConfigs []*BotConfig `json:"botConfigs"`
    12  	CexConfigs []*CEXConfig `json:"cexConfigs"`
    13  }
    14  
    15  func (cfg *MarketMakingConfig) Copy() *MarketMakingConfig {
    16  	c := &MarketMakingConfig{
    17  		BotConfigs: make([]*BotConfig, len(cfg.BotConfigs)),
    18  		CexConfigs: make([]*CEXConfig, len(cfg.CexConfigs)),
    19  	}
    20  	copy(c.BotConfigs, cfg.BotConfigs)
    21  	copy(c.CexConfigs, cfg.CexConfigs)
    22  	return c
    23  }
    24  
    25  // CEXConfig is a configuration for connecting to a CEX API.
    26  type CEXConfig struct {
    27  	// Name is the name of the cex.
    28  	Name string `json:"name"`
    29  	// APIKey is the API key for the CEX.
    30  	APIKey string `json:"apiKey"`
    31  	// APISecret is the API secret for the CEX.
    32  	APISecret string `json:"apiSecret"`
    33  }
    34  
    35  // AutoRebalanceConfig configures deposits and withdrawals by setting minimum
    36  // transfer sizes. Minimum transfer sizes should be set to prevent excessive
    37  // fees on high-fee blockchains. To calculate a minimum transfer size for an
    38  // asset, choose a fee-loss tolerance <= your profit target. If you only wanted to
    39  // lose a maximum of 1% to transfers, and the fees associated with a transfer
    40  // are 350 Sats, then your minimum transfer size might be set to
    41  // 350 * (1 / 0.01) = 35000 Sats.
    42  // For low-fee assets, a transfer size of zero would be perfectly fine in most
    43  // cases, but using a higher value prevents churn.
    44  // For obvious reasons, minimum transfer sizes should never be more than the
    45  // total amount allocated for trading.
    46  // The way these are configured will probably be changed to better capture the
    47  // reasoning above.
    48  type AutoRebalanceConfig struct {
    49  	MinBaseTransfer  uint64 `json:"minBaseTransfer"`
    50  	MinQuoteTransfer uint64 `json:"minQuoteTransfer"`
    51  }
    52  
    53  // BotBalanceAllocation is the initial allocation of funds for a bot.
    54  type BotBalanceAllocation struct {
    55  	DEX map[uint32]uint64 `json:"dex"`
    56  	CEX map[uint32]uint64 `json:"cex"`
    57  }
    58  
    59  // BotInventoryDiffs is the amount of funds to add or remove from a bot's
    60  // allocation.
    61  type BotInventoryDiffs struct {
    62  	DEX map[uint32]int64 `json:"dex"`
    63  	CEX map[uint32]int64 `json:"cex"`
    64  }
    65  
    66  // balanceDiffsToAllocations converts a BotInventoryDiffs to a
    67  // BotBalanceAllocation by removing all negative diffs.
    68  func balanceDiffsToAllocation(diffs *BotInventoryDiffs) *BotBalanceAllocation {
    69  	allocations := &BotBalanceAllocation{
    70  		DEX: make(map[uint32]uint64, len(diffs.DEX)),
    71  		CEX: make(map[uint32]uint64, len(diffs.CEX)),
    72  	}
    73  
    74  	for assetID, diff := range diffs.DEX {
    75  		if diff > 0 {
    76  			allocations.DEX[assetID] += uint64(diff)
    77  		}
    78  	}
    79  	for assetID, diff := range diffs.CEX {
    80  		if diff > 0 {
    81  			allocations.CEX[assetID] += uint64(diff)
    82  		}
    83  	}
    84  
    85  	return allocations
    86  }
    87  
    88  // #### IMPORTANT ###
    89  // If non-backwards compatible changes are made to the BotConfig, a new version
    90  // should be created and the event log db should be updated to support both
    91  // versions.
    92  
    93  // BotConfig is the configuration for a market making bot.
    94  // The balance fields are the initial amounts that will be reserved to use for
    95  // this bot. As the bot trades, the amounts reserved for it will be updated.
    96  type BotConfig struct {
    97  	Host    string `json:"host"`
    98  	BaseID  uint32 `json:"baseID"`
    99  	QuoteID uint32 `json:"quoteID"`
   100  
   101  	BaseWalletOptions  map[string]string `json:"baseWalletOptions"`
   102  	QuoteWalletOptions map[string]string `json:"quoteWalletOptions"`
   103  
   104  	CEXName string `json:"cexName"`
   105  
   106  	// UIConfig is settings defined and used by the front end to determine
   107  	// allocations.
   108  	UIConfig json.RawMessage `json:"uiConfig,omitempty"`
   109  
   110  	// RPCConfig can be used for file-based initial allocations and
   111  	// auto-rebalance settings.
   112  	RPCConfig *struct {
   113  		Alloc         *BotBalanceAllocation `json:"alloc"`
   114  		AutoRebalance *AutoRebalanceConfig  `json:"autoRebalance"`
   115  	} `json:"rpcConfig"`
   116  
   117  	// Only one of the following configs should be set
   118  	BasicMMConfig        *BasicMarketMakingConfig `json:"basicMarketMakingConfig,omitempty"`
   119  	SimpleArbConfig      *SimpleArbConfig         `json:"simpleArbConfig,omitempty"`
   120  	ArbMarketMakerConfig *ArbMarketMakerConfig    `json:"arbMarketMakingConfig,omitempty"`
   121  }
   122  
   123  func (c *BotConfig) requiresPriceOracle() bool {
   124  	return c.BasicMMConfig != nil
   125  }
   126  
   127  func (c *BotConfig) requiresCEX() bool {
   128  	return c.SimpleArbConfig != nil || c.ArbMarketMakerConfig != nil
   129  }
   130  
   131  // multiSplitBuffer returns the additional buffer to add to the order size
   132  // when doing a multi-split. This only applies to the quote asset.
   133  func (c *BotConfig) multiSplitBuffer() float64 {
   134  	if c.QuoteWalletOptions == nil {
   135  		return 0
   136  	}
   137  	multiSplitBuffer, ok := c.QuoteWalletOptions["multisplitbuffer"]
   138  	if !ok {
   139  		return 0
   140  	}
   141  	multiSplitBufferFloat, err := strconv.ParseFloat(multiSplitBuffer, 64)
   142  	if err != nil {
   143  		return 0
   144  	}
   145  	return multiSplitBufferFloat
   146  }
   147  
   148  // maxPlacements returns the max amount of placements this bot will place on
   149  // either side of the market in an epoch.
   150  func (c *BotConfig) maxPlacements() (buy, sell uint32) {
   151  	switch {
   152  	case c.SimpleArbConfig != nil:
   153  		return 1, 1
   154  	case c.ArbMarketMakerConfig != nil:
   155  		return uint32(len(c.ArbMarketMakerConfig.BuyPlacements)), uint32(len(c.ArbMarketMakerConfig.SellPlacements))
   156  	case c.BasicMMConfig != nil:
   157  		return uint32(len(c.BasicMMConfig.BuyPlacements)), uint32(len(c.BasicMMConfig.SellPlacements))
   158  	default:
   159  		return 1, 1
   160  	}
   161  }
   162  
   163  func dexMarketID(host string, base, quote uint32) string {
   164  	return fmt.Sprintf("%s-%d-%d", host, base, quote)
   165  }