Git Product home page Git Product logo

hands-on-elixir-and-otp-cryptocurrency-trading-bot-source-code's Introduction

create-a-cryptocurrency-trading-bot-in-elixir

Resouces related to the "Create a cryptocurrency trading bot in Elixir" book

hands-on-elixir-and-otp-cryptocurrency-trading-bot-source-code's People

Contributors

cinderella-man avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hands-on-elixir-and-otp-cryptocurrency-trading-bot-source-code's Issues

Clean DBs, can't create a new trader...

Through the book to Chapter 15 and all has worked, until now. I can't save "orders" to the data_warehouse db. So, I started with cleaning the DBs out, recreating, remigrating (and reseeding the events from the XRP history file). Now I get

iex(1)> Naive.start_trading("xrpusdt")
11:50:54.299 [info]  Starting Elixir.Naive.SymbolSupervisor worker for XRPUSDT
** (FunctionClauseError) no function clause matching in Ecto.Changeset.change/2    
    
    The following arguments were given to Ecto.Changeset.change/2:
    
        # 1
        nil
    
        # 2
        %{status: "on"}
    
    Attempted function clauses (showing 4 out of 4):
    
        def change({data, types}, changes) when is_map(data)
        def change(%Ecto.Changeset{types: nil}, _changes)
        def change(%Ecto.Changeset{changes: changes, types: types} = changeset, new_changes) when is_map(new_changes) or is_list(new_changes)
        def change(%{__struct__: struct} = data, changes) when is_map(changes) or is_list(changes)
    
    (ecto 3.5.8) lib/ecto/changeset.ex:376: Ecto.Changeset.change/2
    (core 0.1.0) lib/core/service_supervisor.ex:110: Core.ServiceSupervisor.update_status/4
    (core 0.1.0) lib/core/service_supervisor.ex:77: Core.ServiceSupervisor.start_worker/5

Obviously there is nothing in the DB, so no status to update. But for some reason I thought there was a step to get all the symbols from Binance, and load that out. But can't find it for the life of me. Anyway, that wouldn't solve the problem because XRP isn't there anymore.

Any ideas on how to optimally handle this from the ServiceSupervisor? Since we're abstracted out to the scheme, maybe to an upsert?

{:error, %Binance.InsufficientBalanceError{}} when Binance account has sufficient balance

Hi Kamil,

Sometimes I received a {:error, %Binance.InsufficientBalanceError{reason: %{code: -2010, msg: "Account has insufficient balance for requested action."}}} message from Binance API while trying your solution for trading crypto in production environment.

I am using the source code of chapter 17 and I have sufficient balance in my Binance account.

This error occurs in Naive.Trader module when it calls:

  • {:ok, %Binance.OrderResponse{} = order} = @binance_client.order_limit_buy(symbol, quantity, price, "GTC") or
  • {:ok, %Binance.OrderResponse{} = order} = @binance_client.order_limit_sell(symbol, quantity, sell_price, "GTC")

Here are the logs:

            0:38:39.505 [info]  Trader(1633078420000) finished trade cycle for ADAEUR
             
            10:38:39.505 [info]  ADAEUR trader finished trade - restarting
             
            10:38:39.505 [info]  Initializing new trader(1633081119505) for ADAEUR
             
            10:38:42.780 [info]  The trader(1633081119505) is placing a BUY order for ADAEUR @ 1.86600000, quantity: 12.80000000
             
            10:49:07.846 [info]  Trader's(1633081119505 ADAEUR buy order got partially filled
             
            10:49:08.661 [info]  The trader(1633081119505) is placing a SELL order for ADAEUR @ 1.87100000, quantity: 12.80000000.

            10:49:09.479 [error] GenServer #PID<0.3395.0> terminating
            ** (MatchError) no match of right hand side value: {:error, %Binance.InsufficientBalanceError{reason: %{code: -2010, msg: "Account has insufficient balance for requested action."}}}
                (naive 0.1.0) lib/naive/trader.ex:142: Naive.Trader.handle_info/2
                (stdlib 3.15.2) gen_server.erl:695: :gen_server.try_dispatch/4
                (stdlib 3.15.2) gen_server.erl:771: :gen_server.handle_msg/6
                (stdlib 3.15.2) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
            Last message: %Core.Struct.TradeEvent{buyer_market_maker: true, buyer_order_id: 216896572, event_time: 1633081748113, event_type: "trade", price: "1.86600000", quantity: "7.00000000", seller_order_id: 216897971, symbol: "ADAEUR", trade_id: 16058384, trade_time: 1633081748112}
             
            10:49:09.497 [error] GenServer :"Elixir.Naive.Leader-ADAEUR" terminating
            ** (Protocol.UndefinedError) protocol String.Chars not implemented for {{:badmatch, {:error, %Binance.InsufficientBalanceError{reason: %{code: -2010, msg: "Account has insufficient balance for requested action."}}}}, [{Naive.Trader, :handle_info, 2, [file: 'lib/naive/trader.ex', line: 142]}, {:gen_server, :try_dispatch, 4, [file: 'gen_server.erl', line: 695]}, {:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 771]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 226]}]} of type Tuple. This protocol is implemented for the following type(s): Postgrex.Query, Postgrex.Copy, Decimal, BitString, Atom, Integer, NaiveDateTime, DateTime, Version.Requirement, Time, List, Float, Date, URI, Version
                (elixir 1.12.2) lib/string/chars.ex:3: String.Chars.impl_for!/1
                (elixir 1.12.2) lib/string/chars.ex:22: String.Chars.to_string/1
                (naive 0.1.0) lib/naive/leader.ex:180: Naive.Leader.handle_info/2
                (stdlib 3.15.2) gen_server.erl:695: :gen_server.try_dispatch/4
                (stdlib 3.15.2) gen_server.erl:771: :gen_server.handle_msg/6
                (stdlib 3.15.2) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
            Last message: {:DOWN, #Reference<0.3730660033.40632321.49514>, :process, #PID<0.3395.0>, {{:badmatch, {:error, %Binance.InsufficientBalanceError{reason: %{code: -2010, msg: "Account has insufficient balance for requested action."}}}}, [{Naive.Trader, :handle_info, 2, [file: 'lib/naive/trader.ex', line: 142]}, {:gen_server, :try_dispatch, 4, [file: 'gen_server.erl', line: 695]}, {:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 771]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 226]}]}}
             
            10:49:13.640 [info]  Initializing new trader(1633081753640) for ADAEUR
             
            10:49:18.591 [info]  The trader(1633081753640) is placing a BUY order for ADAEUR @ 1.86200000, quantity: 12.80000000

            11:25:11.583 [error] GenServer #PID<0.4469.0> terminating
            ** (MatchError) no match of right hand side value: {:error, %Binance.InsufficientBalanceError{reason: %{code: -2010, msg: "Account has insufficient balance for requested action."}}}
                (naive 0.1.0) lib/naive/trader.ex:79: Naive.Trader.handle_info/2
                (stdlib 3.15.2) gen_server.erl:695: :gen_server.try_dispatch/4
                (stdlib 3.15.2) gen_server.erl:771: :gen_server.handle_msg/6
                (stdlib 3.15.2) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
            Last message: %Core.Struct.TradeEvent{buyer_market_maker: false, buyer_order_id: 216902085, event_time: 1633083910940, event_type: "trade", price: "1.86600000", quantity: "88.80000000", seller_order_id: 216901857, symbol: "ADAEUR", trade_id: 16059034, trade_time: 1633083910940}
             
            11:25:11.584 [error] GenServer :"Elixir.Naive.Leader-ADAEUR" terminating
            ** (Protocol.UndefinedError) protocol String.Chars not implemented for {{:badmatch, {:error, %Binance.InsufficientBalanceError{reason: %{code: -2010, msg: "Account has insufficient balance for requested action."}}}}, [{Naive.Trader, :handle_info, 2, [file: 'lib/naive/trader.ex', line: 79]}, {:gen_server, :try_dispatch, 4, [file: 'gen_server.erl', line: 695]}, {:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 771]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 226]}]} of type Tuple. This protocol is implemented for the following type(s): Postgrex.Query, Postgrex.Copy, Decimal, BitString, Atom, Integer, NaiveDateTime, DateTime, Version.Requirement, Time, List, Float, Date, URI, Version
                (elixir 1.12.2) lib/string/chars.ex:3: String.Chars.impl_for!/1
                (elixir 1.12.2) lib/string/chars.ex:22: String.Chars.to_string/1
                (naive 0.1.0) lib/naive/leader.ex:180: Naive.Leader.handle_info/2
                (stdlib 3.15.2) gen_server.erl:695: :gen_server.try_dispatch/4
                (stdlib 3.15.2) gen_server.erl:771: :gen_server.handle_msg/6
                (stdlib 3.15.2) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
            Last message: {:DOWN, #Reference<0.3730660033.40632322.112313>, :process, #PID<0.4469.0>, {{:badmatch, {:error, %Binance.InsufficientBalanceError{reason: %{code: -2010, msg: "Account has insufficient balance for requested action."}}}}, [{Naive.Trader, :handle_info, 2, [file: 'lib/naive/trader.ex', line: 79]}, {:gen_server, :try_dispatch, 4, [file: 'gen_server.erl', line: 695]}, {:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 771]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 226]}]}}

As you can see, I am trading successfully and then suddenly I start getting errors due to insufficient balance but when I checked the Binance app I noticed that I have enough balance for the operation.

When the error occurs in {:ok, %Binance.OrderResponse{} = order} = @binance_client.order_limit_buy(symbol, quantity, price, "GTC") call the supervisor keeps restarting a new trader and eventually the trader receives a {:ok, %Binance.OrderResponse{} = order} message and continues.

In the other case, when the error occurs in {:ok, %Binance.OrderResponse{} = order} = @binance_client.order_limit_sell(symbol, quantity, sell_price, "GTC") the supervisor restarts a new trader which expects a trade event to place a new sell order but this trade event has already broadcasted when the error firstly occur. Consequently, the trader get stuck in that state and I have to manually sell the crypto in Binance app and to restart everything.

I think this error occurs due to some synchronization problem within the Binance data warehouses, so I modified the code to acknowledge this problem.

In Naive.Trader:

            def handle_info(
                    %TradeEvent{price: price},
                    %State{
                      id: id,
                      symbol: symbol,
                      budget: budget,
                      buy_order: nil,
                      buy_down_interval: buy_down_interval,
                      tick_size: tick_size,
                      step_size: step_size
                    } = state
                  ) do
                price = calculate_buy_price(price, buy_down_interval, tick_size)

                quantity = calculate_quantity(budget, price, step_size)

                @logger.info(
                  "The trader(#{id}) is placing a BUY order " <>
                    "for #{symbol} @ #{price}, quantity: #{quantity}"
                )

               new_state = case @binance_client.order_limit_buy(symbol, quantity, price, "GTC") do # => BEGIN UPDATE
                  {:ok, %Binance.OrderResponse{} = order} ->
                    :ok = broadcast_order(order)
                    new_state = %{state | buy_order: order}
                    @leader.notify(:trader_state_updated, new_state)
                    new_state

                  {:error, %Binance.InsufficientBalanceError{reason: reason}} ->
                    @logger.info(
                      "The trader(#{id}) recived an ERROR:  " <>
                        "#{reason}"
                    )
                    state
                end

                {:noreply, new_state}
              end


            ...

            def handle_info(
                    %TradeEvent{
                      buyer_order_id: order_id
                    } = trade_event,
                    %State{
                      id: id,
                      symbol: symbol,
                      buy_order:
                        %Binance.OrderResponse{
                          price: buy_price,
                          order_id: order_id,
                          orig_qty: quantity,
                          transact_time: timestamp
                        } = buy_order,
                      profit_interval: profit_interval,
                      tick_size: tick_size
                    } = state
                  ) do
                {:ok, %Binance.Order{} = current_buy_order} =
                  @binance_client.get_order(
                    symbol,
                    timestamp,
                    order_id
                  )

                :ok = broadcast_order(current_buy_order)

                buy_order = %{buy_order | status: current_buy_order.status}

                {operation_status, new_state} =
                  if buy_order.status == "FILLED" do
                    sell_price = calculate_sell_price(buy_price, profit_interval, tick_size)

                    @logger.info(
                      "The trader(#{id}) is placing a SELL order for " <>
                        "#{symbol} @ #{sell_price}, quantity: #{quantity}."
                    )

                    case @binance_client.order_limit_sell(symbol, quantity, sell_price, "GTC") do # => BEGIN UPDATE
                      {:ok, %Binance.OrderResponse{} = order} ->
                        :ok = broadcast_order(order)
                        {:ok, %{state | buy_order: buy_order, sell_order: order}}

                      {:error, %Binance.InsufficientBalanceError{reason: reason}} ->
                        @logger.info(
                          "The trader(#{id}) recived an ERROR:  " <>
                            "#{reason}"
                        )

                        {:error, state}
                    end
                  else
                    @logger.info("Trader's(#{id}) #{symbol} buy order got partially filled")
                    {:ok, %{state | buy_order: buy_order}}
                  end

                case operation_status do
                  :ok -> @leader.notify(:trader_state_updated, new_state)
                  :error -> @leader.notify(:rebroadcast_trade_event, trade_event)
                end

                {:noreply, new_state}
              end

And in the Naive.Leader:

            def notify(:rebroadcast_trade_event, trade_event) do
                Phoenix.PubSub.broadcast(
                  Core.PubSub,
                  "TRADE_EVENTS:#{trade_event.symbol}",
                  trade_event
                )
              end

So, let me know your thoughts about this kind of problem and if you have another solution to solve it.

Thank you very much for your attention!

André Santos

Offering styling for Piping

Hey, thanks so much for all of your work in this book, I've followed
along when I first started learning Elixir and have investigated more
recently, having been able to understand more of what's going on now.
It's been a great help on my Elixir journey.

It's been great going through the book process of building a clever
umbrella app one step at a time and then refactoring it and having the
"why" explained.
If you wanted to add on to this about how piping can help readability
then maybe you'd want to include a refactor in
/apps/naive/lib/naive/strategy.ex such as:

 def calculate_sell_price(buy_price, profit_interval, tick_size) do
   fee = "1.001"
-  original_price = D.mult(buy_price, fee)
+  adjusted_profit_interval = profit_interval |> D.add("1.0")
 
-  net_target_price =
-    D.mult(
-      original_price,
-      D.add("1.0", profit_interval)
-    )
-
-  gross_target_price = D.mult(net_target_price, fee)
-
-  D.to_string(
-    D.mult(
-      D.div_int(gross_target_price, tick_size),
-      tick_size
-    ),
-    :normal
-  )
+  buy_price
+  |> D.mult(fee)
+  |> D.mult(adjusted_profit_interval)
+  |> D.mult(fee)
+  |> D.div_int(tick_size)
+  |> D.mult(tick_size)
+  |> D.to_string(:normal)
 end
 
 def calculate_buy_price(current_price, buy_down_interval, tick_size) do
   # not necessarily legal price
-  exact_buy_price =
-    D.sub(
-      current_price,
-      D.mult(current_price, buy_down_interval)
-    )
+  buy_down_price = current_price |> D.mult(buy_down_interval)
 
-  D.to_string(
-    D.mult(
-      D.div_int(exact_buy_price, tick_size),
-      tick_size
-    ),
-    :normal
-  )
+  current_price
+  |> D.sub(buy_down_price)
+  |> D.div_int(tick_size)
+  |> D.mult(tick_size)
+  |> D.to_string(:normal)
 end
 
 def calculate_quantity(budget, price, step_size) do
   # not necessarily legal quantity
-  exact_target_quantity = D.div(budget, price)
-
-  D.to_string(
-    D.mult(
-      D.div_int(exact_target_quantity, step_size),
-      step_size
-    ),
-    :normal
-  )
+  budget
+  |> D.div(price)
+  |> D.div_int(step_size)
+  |> D.mult(step_size)
+  |> D.to_string(:normal)
 end

I'm really looking forward to any future updates you make and would
recommend your book to anyone else thinking about it as it's been a
great process to learn some of the finer details of how Elixir can be
used. Thanks again!

Chapter 02 - error: Streamer.Binance.OrderResponse.__struct__/0 is undefined,

Hello,

i am currently working through the book and i am stuck within chapter 02 Create a naive traing strategy on page 27.

# /apps/naive/lib/naive/trader.ex
def handle_cast(
      %TradeEvent{price: price},
      %State{symbol: symbol, buy_order: nil} = state
    ) do

  quantity = "100" # <= Hardcoded until chapter 7
  Logger.info("Placing BUY order for #{symbol} @ #{price}, quantity: #{quantity}")

  {:ok, %Binance.OrderResponse{} = order} =
    Binance.order_limit_buy(symbol, quantity, price, "GTC")

  {:noreply, %{state | buy_order: order}}
end

When i am running iex -S mix the compiler is complaining about

Compiling 3 files (.ex)
error: Streamer.Binance.OrderResponse.__struct__/0 is undefined, cannot expand struct Streamer.Binance.OrderResponse. Make sure the struct name is correct. If the struct name exists and is correct but it still cannot be found, you likely have cyclic module usage in your code
  lib/naive/trader.ex:47: Naive.Trader.handle_cast/2


== Compilation error in file lib/naive/trader.ex ==
** (CompileError) lib/naive/trader.ex: cannot compile module Naive.Trader (errors have been logged)

I looked into the Binance folder within deps/binance/lib/binance/structs/order_response.ex and found the OrderResponse struct, so i am not really sure what i am missing.

Appreciate your help, thanks!

Order does not exist

Hi, thanks for sharing the code for the book.

I was doing some experiments and this happened:

18:53:28.073 [info]  Rebuy triggered for XRPUSDT by the trader(1612896801530)

18:53:28.073 [info]  Starting new trader for XRPUSDT

18:53:28.074 [info]  Initializing new trader(1612896808074) for XRPUSDT

18:53:28.082 [info]  The trader(1612896808074) is placing a BUY order for XRPUSDT @ 0.47422, quantity: 24.2

18:53:28.756 [error] GenServer #PID<0.428.0> terminating
** (MatchError) no match of right hand side value: {:error, %{"code" => -2013, "msg" => "Order does not exist."}}
    (naive 0.1.0) lib/naive/trader.ex:117: Naive.Trader.handle_info/2
    (stdlib 3.13.2) gen_server.erl:680: :gen_server.try_dispatch/4
    (stdlib 3.13.2) gen_server.erl:756: :gen_server.handle_msg/6
    (stdlib 3.13.2) proc_lib.erl:226: :proc_lib.init_p_do_apply/3

Any idea in what situations the order can fail to be found?

Thanks!

Compilation error in chapter_15 after recent commit

== Compilation error in file lib/binance_mock.ex ==
** (CompileError) lib/binance_mock.ex:275: undefined function symbol/0

A recent commit removed the local variable "symbol".
I changed "symbol" to "trade_event.symbol" to fix this.

Thanks a lot for your book and the great sample code!

Getting an error trying to run the first actual test against Binance api

Hey, i've ran in to a problem here link in book

19:38:08.647 [error] GenServer :trader terminating
** (stop) {:badarg, {'mac.c', 216}, 'Bad key'}
    (crypto 4.8.3) :crypto.mac_nif(:hmac, :sha256, nil, "price=0.94420000&quantity=10&recvWindow=1000&side=BUY&symbol=XRPUSDT&timeInForce=GTC&timestamp=1632674288644&type=LIMIT")
    (binance 1.0.1) lib/binance/rest/http_client.ex:76: Binance.Rest.HTTPClient.signed_request_binance/3
    (binance 1.0.1) lib/binance.ex:384: Binance.create_order/11
    (binance 1.0.1) lib/binance.ex:422: Binance.order_limit_buy/4
    (naive 0.1.0) lib/naive/trader.ex:48: Naive.Trader.handle_cast/2
    (stdlib 3.14) gen_server.erl:689: :gen_server.try_dispatch/4
    (stdlib 3.14) gen_server.erl:765: :gen_server.handle_msg/6
    (stdlib 3.14) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
Last message: {:"$gen_cast", %Streamer.Binance.TradeEvent{buyer_market_maker: true, buyer_order_id: 3319802220, event_time: 1632674288500, event_type: "trade", price: "0.94420000", quantity: "27.00000000", seller_order_id: 3319802263, symbol: "XRPUSDT", trade_id: 344326919, trade_time: 1632674288500}}
** (EXIT from #PID<0.339.0>) shell process exited with reason: an exception was raised:
    ** (ErlangError) Erlang error: {:badarg, {'mac.c', 216}, 'Bad key'}
        (crypto 4.8.3) :crypto.mac_nif(:hmac, :sha256, nil, "price=0.94420000&quantity=10&recvWindow=1000&side=BUY&symbol=XRPUSDT&timeInForce=GTC&timestamp=1632674288644&type=LIMIT")
        (binance 1.0.1) lib/binance/rest/http_client.ex:76: Binance.Rest.HTTPClient.signed_request_binance/3
        (binance 1.0.1) lib/binance.ex:384: Binance.create_order/11
        (binance 1.0.1) lib/binance.ex:422: Binance.order_limit_buy/4
        (naive 0.1.0) lib/naive/trader.ex:48: Naive.Trader.handle_cast/2
        (stdlib 3.14) gen_server.erl:689: :gen_server.try_dispatch/4
        (stdlib 3.14) gen_server.erl:765: :gen_server.handle_msg/6
        (stdlib 3.14) proc_lib.erl:226: :proc_lib.init_p_do_apply/3

In some cases, How to tell to the supervisor stop restarting the trader?

@Cinderella-Man thanks, for your book, it has been really interesting and useful to understand more about Elixir.

I was not sure if it could be the best place to ask questions. If you think that this question is not related to the book please close the issue.

Sometimes when something was wrong when an order is created an error is returned.

{:error, {:binance_error, %{code: -1013, msg: "Filter failure: MIN_NOTIONAL"}}}

it doesn't match with

    {:ok, %Binance.OrderResponse{} = order} =
      @binance_client.order_limit_buy(symbol, quantity, price, "GTC")

and the trader is restarted. Great.

But maybe under some circumstances could be useful if the trader stops being restarted, for example, because you need to change some settings.

Does exist some way to tell to the supervisor: stop restarting the trader?

I was thinking about how to match some error cases

    new_state =
      case @binance_client.order_limit_buy(symbol, quantity, price, "GTC") do
        {:ok, %Binance.OrderResponse{} = order} ->
          new_state = %{state | buy_order: order}
          Naive.Leader.notify(:trader_state_updated, new_state)
          new_state

        {:error, {:error, {:binance_error, %{code: -1013}}}} ->
          Naive.Leader.notify(:critical_error, state)
          state
      end

but I am not sure about which could be a good way to tell to the supervisor stop restarting the trader.

Or maybe that is not the Elixir way to do things.
What do you think?

Thanks in advice for your feedback.

The full log of those types of cases.

2021-06-20 17:32:45.718 [error] GenServer #PID<0.341.0> terminating
** (FunctionClauseError) no function clause matching in Binance.parse_order_response/1
    (binance 1.0.1) lib/binance.ex:505: Binance.parse_order_response({:error, {:binance_error, %{code: -1013, msg: "Filter failure: MIN_NOTIONAL"}}})
    (naive 0.1.0) lib/naive/trader.ex:77: Naive.Trader.handle_info/2
    (stdlib 3.15.1) gen_server.erl:695: :gen_server.try_dispatch/4
    (stdlib 3.15.1) gen_server.erl:771: :gen_server.handle_msg/6
    (stdlib 3.15.1) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
Last message: %Streamer.Binance.TradeEvent{buyer_market_maker: false, buyer_order_id:, event_time: 1624210365370, event_type: "trade", price: "1.39800000", quantity: "10.86000000", seller_order_id:, symbol: "ADAUSDT", trade_id:, trade_time: 1624210365370}
State: %Naive.Trader.State{budget: #Decimal<10>, buy_down_interval: "0.002", buy_order: nil, id:, profit_interval: "0.0012", rebuy_interval: "0.0035", rebuy_notified: false, sell_order: nil, step_size: "0.01000000", symbol: "ADAUSDT", tick_size: "0.00010000"}

]}, {Naive.Trader, :handle_info, 2, [file: 'lib/naive/trader.ex', line: 77]}, {:gen_server, :try_dispatch, 4, [file: 'gen_server.erl', line: 695]},
{:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 771]},
{:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 226]}]} of type Tuple. This protocol is implemented for the following type(s): Decimal, Version.Requirement, Time, DateTime, Integer, List, Version, URI, Atom, BitString, Date, Float, NaiveDateTime
    (elixir 1.12.1) lib/string/chars.ex:3: String.Chars.impl_for!/1
    (elixir 1.12.1) lib/string/chars.ex:22: String.Chars.to_string/1
    (naive 0.1.0) lib/naive/leader.ex:133: Naive.Leader.handle_info/2
    (stdlib 3.15.1) gen_server.erl:695: :gen_server.try_dispatch/4
    (stdlib 3.15.1) gen_server.erl:771: :gen_server.handle_msg/6
    (stdlib 3.15.1) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
Last message: {:DOWN, #Reference<0.1217684777.3447455745.34513>, :process, #PID<0.341.0>, {:function_clause, [{Binance, :parse_order_response, [error: {:binance_error, %{code: -1013, msg: "Filter failure: MIN_NOTIONAL"}}],
[file: 'lib/binance.ex', line: 505]}, {Naive.Trader, :handle_info, 2, [file: 'lib/naive/trader.ex', line: 77]},
{:gen_server, :try_dispatch, 4, [file: 'gen_server.erl', line: 695]},
{:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 771]},
{:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 226]}]}}
State: %Naive.Leader.State{settings: %{budget: 30, buy_down_interval: "0.002", chunks: 3, profit_interval: "0.0012", rebuy_interval: "0.0035", step_size: "0.01000000", symbol: "ADAUSDT", tick_size: "0.00010000"}, symbol: "ADAUSDT", traders:
[%Naive.Leader.TraderData{pid: #PID<0.341.0>, ref: #Reference<0.1217684777.3447455745.34513>,
state: %Naive.Trader.State{budget: #Decimal<10>, buy_down_interval: "0.002", buy_order: nil, id: 1624210365312, profit_interval: "0.0012", rebuy_interval: "0.0035", rebuy_notified: false, sell_order: nil, step_size: "0.01000000", symbol: "ADAUSDT", tick_size: "0.00010000"}}]}

Thanks again.

WebSockex timeout error

Streamer.start_streaming("xrpusdt")
{:error, %WebSockex.ConnError{original: :timeout}}

is there anyone have websockex ConnError timeout error ?

Duplicated image on chapter 3

Hi!
First of all thanks for this book, it covers a lot of useful elixir topics with a concrete interesting project and I'm really enjoying it.
I think that image at the end of 3.2 is duplicated, it should show some sort of database store process as described in the paragraph.

SSL problems at startup?

When I recently tried your code under Elixir 1.12, I had SSL problems that prevented iex -S mix from running (see stack trace below). Even worse, when I tried using 1.11 I had the same problem.

Have you had any similar problems with SSL?

¨¨
Ranch listener SurveyAPIWeb.Endpoint.HTTPS had connection process started with :cowboy_tls:start_link/4 at #PID<0.454.0> exit with reason: {:undef, [{:ssl, :ssl_accept, [{:sslsocket, {:gen_tcp, #Port<0.22>, :tls_connection, [option_tracker: #PID<0.346.0>, session_tickets_tracker: :disabled, session_id_tracker: #PID<0.347.0>]}, [#PID<0.452.0>, #PID<0.451.0>]}, [], 5000], []}, {:ranch_ssl, :handshake, 3, [file: '/Users/jonas/ex/survey_api/deps/ranch/src/ranch_ssl.erl', line: 142]}, {:ranch, :handshake, 2, [file: '/Users/jonas/ex/survey_api/deps/ranch/src/ranch.erl', line: 243]}, {:cowboy_tls, :connection_process, 4, [file: '/Users/jonas/ex/survey_api/deps/cowboy/src/cowboy_tls.erl', line: 43]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 226]}]
¨¨

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.