forked from thrasher-corp/gocryptotrader
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
poloniex: websocket update (thrasher-corp#659)
* poloniex: websocket update with debug output and currency tracking system * linter: fix issues * nits: Addr * poloniex: govet fix * nits: addr * Bittrex: Fix fee test
- Loading branch information
Showing
12 changed files
with
4,114 additions
and
426 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
package poloniex | ||
|
||
import ( | ||
"errors" | ||
"strconv" | ||
"sync" | ||
|
||
"github.com/thrasher-corp/gocryptotrader/currency" | ||
) | ||
|
||
// CurrencyDetails stores a map of currencies associated with their ID | ||
type CurrencyDetails struct { | ||
pairs map[float64]PairSummaryInfo | ||
codes map[float64]CodeSummaryInfo | ||
// Mutex used for future when we will periodically update this table every | ||
// week or so in production | ||
m sync.RWMutex | ||
} | ||
|
||
// PairSummaryInfo defines currency pair information | ||
type PairSummaryInfo struct { | ||
Pair currency.Pair | ||
IsFrozen bool | ||
PostOnly bool | ||
} | ||
|
||
// CodeSummaryInfo defines currency information | ||
type CodeSummaryInfo struct { | ||
Currency currency.Code | ||
WithdrawalTXFee float64 | ||
MinimumConfirmations int64 | ||
DepositAddress string | ||
WithdrawalDepositDisabled bool | ||
Frozen bool | ||
} | ||
|
||
var ( | ||
errCannotLoadNoData = errors.New("cannot load websocket currency data as data is nil") | ||
errNoDepositAddress = errors.New("no public deposit address for currency") | ||
errPairMapIsNil = errors.New("cannot get currency pair, map is nil") | ||
errCodeMapIsNil = errors.New("cannot get currency code, map is nil") | ||
errCurrencyNotFoundInMap = errors.New("currency not found") | ||
) | ||
|
||
// loadPairs loads currency pair associations with unique identifiers from | ||
// ticker data map | ||
func (w *CurrencyDetails) loadPairs(data map[string]Ticker) error { | ||
if data == nil { | ||
return errCannotLoadNoData | ||
} | ||
w.m.Lock() | ||
defer w.m.Unlock() | ||
for k, v := range data { | ||
pair, err := currency.NewPairFromString(k) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if w.pairs == nil { | ||
w.pairs = make(map[float64]PairSummaryInfo) | ||
} | ||
w.pairs[v.ID] = PairSummaryInfo{ | ||
Pair: pair, | ||
IsFrozen: v.IsFrozen == 1, | ||
PostOnly: v.PostOnly == 1, | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// loadCodes loads currency codes from currency map | ||
func (w *CurrencyDetails) loadCodes(data map[string]Currencies) error { | ||
if data == nil { | ||
return errCannotLoadNoData | ||
} | ||
w.m.Lock() | ||
defer w.m.Unlock() | ||
for k, v := range data { | ||
if v.Delisted == 1 { | ||
continue | ||
} | ||
|
||
if w.codes == nil { | ||
w.codes = make(map[float64]CodeSummaryInfo) | ||
} | ||
|
||
w.codes[v.ID] = CodeSummaryInfo{ | ||
Currency: currency.NewCode(k), | ||
WithdrawalTXFee: v.TxFee, | ||
MinimumConfirmations: v.MinConfirmations, | ||
DepositAddress: v.DepositAddress, | ||
WithdrawalDepositDisabled: v.WithdrawalDepositDisabled == 1, | ||
Frozen: v.Frozen == 1, | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// GetPair returns a currency pair by its ID | ||
func (w *CurrencyDetails) GetPair(id float64) (currency.Pair, error) { | ||
w.m.RLock() | ||
defer w.m.RUnlock() | ||
if w.pairs == nil { | ||
return currency.Pair{}, errPairMapIsNil | ||
} | ||
|
||
p, ok := w.pairs[id] | ||
if ok { | ||
return p.Pair, nil | ||
} | ||
|
||
// This is here so we can still log an order with the ID as the currency | ||
// pair which you can then cross reference later with the exchange ID list, | ||
// rather than error out. | ||
op, err := currency.NewPairFromString(strconv.FormatFloat(id, 'f', -1, 64)) | ||
if err != nil { | ||
return op, err | ||
} | ||
return op, errIDNotFoundInPairMap | ||
} | ||
|
||
// GetCode returns a currency code by its ID | ||
func (w *CurrencyDetails) GetCode(id float64) (currency.Code, error) { | ||
w.m.RLock() | ||
defer w.m.RUnlock() | ||
if w.codes == nil { | ||
return currency.Code{}, errCodeMapIsNil | ||
} | ||
c, ok := w.codes[id] | ||
if ok { | ||
return c.Currency, nil | ||
} | ||
return currency.Code{}, errIDNotFoundInCodeMap | ||
} | ||
|
||
// GetWithdrawalTXFee returns withdrawal transaction fee for the currency | ||
func (w *CurrencyDetails) GetWithdrawalTXFee(c currency.Code) (float64, error) { | ||
w.m.RLock() | ||
defer w.m.RUnlock() | ||
if w.codes == nil { | ||
return 0, errCodeMapIsNil | ||
} | ||
for _, v := range w.codes { | ||
if v.Currency == c { | ||
return v.WithdrawalTXFee, nil | ||
} | ||
} | ||
return 0, errCurrencyNotFoundInMap | ||
} | ||
|
||
// GetDepositAddress returns the public deposit address details for the currency | ||
func (w *CurrencyDetails) GetDepositAddress(c currency.Code) (string, error) { | ||
w.m.RLock() | ||
defer w.m.RUnlock() | ||
if w.codes == nil { | ||
return "", errCodeMapIsNil | ||
} | ||
for _, v := range w.codes { | ||
if v.Currency == c { | ||
if v.DepositAddress == "" { | ||
return "", errNoDepositAddress | ||
} | ||
return v.DepositAddress, nil | ||
} | ||
} | ||
return "", errCurrencyNotFoundInMap | ||
} | ||
|
||
// IsWithdrawAndDepositsEnabled returns if withdrawals or deposits are enabled | ||
func (w *CurrencyDetails) IsWithdrawAndDepositsEnabled(c currency.Code) (bool, error) { | ||
w.m.RLock() | ||
defer w.m.RUnlock() | ||
if w.codes == nil { | ||
return false, errCodeMapIsNil | ||
} | ||
for _, v := range w.codes { | ||
if v.Currency == c { | ||
return !v.WithdrawalDepositDisabled, nil | ||
} | ||
} | ||
return false, errCurrencyNotFoundInMap | ||
} | ||
|
||
// IsTradingEnabledForCurrency returns if the currency is allowed to be traded | ||
func (w *CurrencyDetails) IsTradingEnabledForCurrency(c currency.Code) (bool, error) { | ||
w.m.RLock() | ||
defer w.m.RUnlock() | ||
if w.codes == nil { | ||
return false, errCodeMapIsNil | ||
} | ||
for _, v := range w.codes { | ||
if v.Currency == c { | ||
return !v.Frozen, nil | ||
} | ||
} | ||
return false, errCurrencyNotFoundInMap | ||
} | ||
|
||
// IsTradingEnabledForPair returns if the currency pair is allowed to be traded | ||
func (w *CurrencyDetails) IsTradingEnabledForPair(pair currency.Pair) (bool, error) { | ||
w.m.RLock() | ||
defer w.m.RUnlock() | ||
if w.codes == nil { | ||
return false, errCodeMapIsNil | ||
} | ||
for _, v := range w.pairs { | ||
if v.Pair.Equal(pair) { | ||
return !v.IsFrozen, nil | ||
} | ||
} | ||
return false, errCurrencyNotFoundInMap | ||
} | ||
|
||
// IsPostOnlyForPair returns if an order is allowed to take liquidity from the | ||
// books or reduce positions | ||
func (w *CurrencyDetails) IsPostOnlyForPair(pair currency.Pair) (bool, error) { | ||
w.m.RLock() | ||
defer w.m.RUnlock() | ||
if w.codes == nil { | ||
return false, errCodeMapIsNil | ||
} | ||
for _, v := range w.pairs { | ||
if v.Pair.Equal(pair) { | ||
return v.PostOnly, nil | ||
} | ||
} | ||
return false, errCurrencyNotFoundInMap | ||
} | ||
|
||
// isInitial checks state of maps to determine if they have been loaded or not | ||
func (w *CurrencyDetails) isInitial() bool { | ||
w.m.RLock() | ||
defer w.m.RUnlock() | ||
return w.codes == nil || w.pairs == nil | ||
} |
Oops, something went wrong.