askmike / bitstamp

Bitstamp REST API wrapper
81 stars 54 forks source link

Invalid nonce error #15

Closed Removed-5an closed 7 years ago

Removed-5an commented 10 years ago

Sometimes an API call will return without an err obj but the result will contain:

{error: "Invalid nonce"}

paulhkulla commented 10 years ago

Any more info on this ?

askmike commented 10 years ago

It could be possible that this happens when the API keys are used multiple times. I will look into this when I have time.

paulhkulla commented 10 years ago

Great, please do keep us updated :)

ghost commented 9 years ago

I have created this Stackoverflow question that explains the situation.

jeroenvanagt commented 7 years ago

I still get nonce errors at Bitstamp. See snipped from my app log below. I also print the generated Nonce to log as soon as it is created.

It seems that they are all sequential, so I cannot explain why I got an error

Nonce: 14776521194160000 Nonce: 14776521194380000 Nonce: 14776521194410000 Nonce: 14776521194420000 Nonce: 14776521194440000 Nonce: 14776521194460000 Nonce: 14776521194470000

[Error: Bitstamp error 403: {"status": "error", "reason": "Invalid nonce", "code": "API0004"}] [Error: Bitstamp error 403: {"status": "error", "reason": "Invalid nonce", "code": "API0004"}]

Could it be that bitstamp is allowing only a Nonce of a certain length causing part of the Nonce to be stripped (and then create duplicated nonces?)

askmike commented 7 years ago

@jeroenvanagt are you sure that you are not using this API key anywhere else?

jeroenvanagt commented 7 years ago

Thanks for your quick response.

No, the API key is only used in a single running app.

The strange thing is that the nonce error happens when I call the bitstamp.sell() function multiple times in a loop. I expected this to work because each call creates it's own Nonce....

As you can see above I make 7 API call's of which 2 return a nonce error.

I have implemented the call as a promise (which is then called in a loop)

 create_order: (type,price,amount) =>
    return new Promise((resolve, reject) =>

      # Reduce the amount to max 8 decimal places
      amount = Math.round(amount * 100000000) / 100000000

      if type == 'buy'

        # Create buy order
        @bitstamp.buy MARKET,amount,price,undefined, (err, result) =>
          if err
            console.log err
            reject(err)
          else
            resolve(result)
      else if type == 'sell'
        # Create sell order
        @bitstamp.sell MARKET,amount,price,undefined, (err, result) =>
          if err
            console.log err
            reject(err)
          else
            resolve(result)
      else
        reject("unknown order type: #{type}")
    )
jeroenvanagt commented 7 years ago

ps As you may have noticed, the code above is coffeescript

askmike commented 7 years ago

I will (hopefully) test this tomorrow!

askmike commented 7 years ago

@jeroenvanagt I can reproduce this error, however I don't see any way to resolve this in the module: if I remove all padding and set the nonce to unix timestamp in ms (4 characters shorter than what it currently is) I still get this error:

for(let i = 0; i < 20; i++)
  privateBitstamp.balance(null, err => console.log(err ? 'ERROR' : 'ok'));

yields:

ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ok
ok
ok
ok

(80% of the requests error).

I think this has to do with Bitstamp's API.. Do you need to create sell orders with the least latency as possible? If not, I'd suggest to throttle sell orders with a few ms or so.

jeroenvanagt commented 7 years ago

I solved the problem by calling the method sequentially without blocking IO using the node-async-loop NPM lib. Here is the code (which is now working)

          asyncLoop pockets, ((pocket, next) =>
            # Calculate total fee paid
            pocket.fee ||= Math.round(pocket.price * pocket.amount * FEE_FACTOR * 100) / 100
            fee = pocket.fee * 2 # Buy and sell fee
            profit_margin = 100 * ((price - pocket.price - fee) / pocket.price)
            if profit_margin > @min_profit_perc
              @sell_now(price,pocket,@trader_id, date).then (result) =>
                results.push(result)
                next()
                return
              .catch (err) =>
                results.push("Error while selling: #{err}")
                next()
                return
            else
              console.log "Not selling: Profit margin (#{profit_margin} %) < min profit margin (#{@min_profit_perc} %)"
              next()
              return
          ), (err) =>
            if err
              resolve(["Problem occured when selling: #{err}"])
            else
              console.log "DEBUG: asyncloop finished"

The @sell_now function calls the @create_order function.

So problem is solved. Thanks for the help.

askmike commented 7 years ago

great!