func (c *RestClient) newRequest(method string, refURL string, params url.Values, body []byte) (*http.Request, error) {
	rel, err := url.Parse(refURL)
	if err != nil {
		return nil, err
	}
	if params != nil {
		rel.RawQuery = params.Encode()
	}
	var req *http.Request
	u := c.BaseURL.ResolveReference(rel)
	req, err = http.NewRequest(method, u.String(), bytes.NewReader(body))
	if err != nil {
		return nil, err
	}
	if addUserAgentHeader {
		req.Header.Add("User-Agent", UserAgent)
	}
	return req, nil
}
NewRequest create new API request. Relative url can be provided in refURL.
package max
import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"reflect"
	"regexp"
	"strconv"
	"sync/atomic"
	"time"
	"github.com/c9s/bbgo/pkg/util"
	"github.com/c9s/bbgo/pkg/version"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
)
const (
	ProductionAPIURL = "https://max-api.maicoin.com/api/v2"
	UserAgent = "bbgo/" + version.Version
	defaultHTTPTimeout = time.Second * 30
	TimestampSince = 1535760000
)
var debugRequestDump = false
var debugMaxRequestPayload = false
var addUserAgentHeader = true
var httpTransportMaxIdleConnsPerHost = http.DefaultMaxIdleConnsPerHost
var httpTransportMaxIdleConns = 100
var httpTransportIdleConnTimeout = 90 * time.Second
func init() {
	debugMaxRequestPayload, _ = util.GetEnvVarBool("DEBUG_MAX_REQUEST_PAYLOAD")
	debugRequestDump, _ = util.GetEnvVarBool("DEBUG_MAX_REQUEST")
	addUserAgentHeader, _ = util.GetEnvVarBool("DISABLE_MAX_USER_AGENT_HEADER")
	if val, ok := util.GetEnvVarInt("HTTP_TRANSPORT_MAX_IDLE_CONNS_PER_HOST"); ok {
		httpTransportMaxIdleConnsPerHost = val
	}
	if val, ok := util.GetEnvVarInt("HTTP_TRANSPORT_MAX_IDLE_CONNS"); ok {
		httpTransportMaxIdleConns = val
	}
	if val, ok := util.GetEnvVarDuration("HTTP_TRANSPORT_IDLE_CONN_TIMEOUT"); ok {
		httpTransportIdleConnTimeout = val
	}
}
var logger = log.WithField("exchange", "max")
var htmlTagPattern = regexp.MustCompile("<[/]?[a-zA-Z-]+.*?>")
var timeOffset int64 = 0
var serverTimestamp = time.Now().Unix()
var reqCount int64 = 1
type RestClient struct {
	client *http.Client
	BaseURL *url.URL
	APIKey    string
	APISecret string
	AccountService    *AccountService
	PublicService     *PublicService
	TradeService      *TradeService
	OrderService      *OrderService
	RewardService     *RewardService
	WithdrawalService *WithdrawalService
}
func NewRestClientWithHttpClient(baseURL string, httpClient *http.Client) *RestClient {
	u, err := url.Parse(baseURL)
	if err != nil {
		panic(err)
	}
	var client = &RestClient{
		client:  httpClient,
		BaseURL: u,
	}
	client.AccountService = &AccountService{client}
	client.TradeService = &TradeService{client}
	client.PublicService = &PublicService{client}
	client.OrderService = &OrderService{client}
	client.RewardService = &RewardService{client}
	client.WithdrawalService = &WithdrawalService{client}
	client.initNonce()
	return client
}
func NewRestClient(baseURL string) *RestClient {
	transport := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}).DialContext,
		ForceAttemptHTTP2:     true,
		MaxIdleConns:          httpTransportMaxIdleConns,
		MaxIdleConnsPerHost:   httpTransportMaxIdleConnsPerHost,
		IdleConnTimeout:       httpTransportIdleConnTimeout,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}
	client := &http.Client{
		Timeout:   defaultHTTPTimeout,
		Transport: transport,
	}
	return NewRestClientWithHttpClient(baseURL, client)
}
func (c *RestClient) Auth(key string, secret string) *RestClient {
	c.APIKey = key
	c.APISecret = secret
	return c
}
func (c *RestClient) initNonce() {
	var clientTime = time.Now()
	var err error
	serverTimestamp, err = c.PublicService.Timestamp()
	if err != nil {
		logger.WithError(err).Panic("failed to sync timestamp with max")
	}
	timeOffset = serverTimestamp - clientTime.Unix()
	logger.Infof("loaded max server timestamp: %d offset=%d", serverTimestamp, timeOffset)
}
func (c *RestClient) getNonce() int64 {
	var seconds = time.Now().Unix()
	var rc = atomic.AddInt64(&reqCount, 1)
	return (seconds+timeOffset)*1000 - 1 + int64(math.Mod(float64(rc), 1000.0))
}