Current section
Files
Jump to
Current section
Files
lib/ig.ex
defmodule Ig do
@moduledoc """
Public interface for using IG Api's wrapper.
It expects following config:
```
config :ig,
users: %{
user_name: %{
identifier: "...",
password: "...",
api_key: "...",
demo: false
}
}
```
where:
- `user_name` is a human readable reference that will be used
to point which user should be used (it can be any valid atom)
- `identifier` is your username
- `api_key` can be obtained from "My Account" on IG's dealing platform
- `demo` confirms is that a demo account
Idea behind config structured this way is that allows to easily use
multiple accounts (for example to minimize the risk) just by referring
to them using freely picked name.
To clarify - account is a whole user profile with assigned email. For
example two accounts would mean that you use two completely seperate
profile with diffent login details, personal details etc. This can be
beneficial when for example one account is classified as "professional
trader" (with high margins available but without many safety gates) and
other one is retail customer (higher premiums but safety features).
It can also be used to mitigate increased margins when trading high volumes.
To sum up:
- account - single per person, you log in with it
- subaccount - listed as "accounts" in My IG
Ig holds spins further server per account and acts as a gateway to execute
any function on the account. It allows you to use multiple accounts in
parallel.
"""
use GenServer
defmodule State do
defstruct users: []
end
## Public interface
@doc """
Required for starting from mix
"""
def start(_type, _args) do
start_link(nil)
end
@spec start_link(any) :: GenServer.on_start()
def start_link(_) do
GenServer.start_link(__MODULE__, nil, name: :IG)
end
@spec init(any) :: {:ok, %State{}}
def init(_) do
users = Enum.map(
Application.get_env(:ig, :users) || [], &init_account/1
) |> Enum.into(%{})
{:ok, %State{
users: users
}}
end
@spec get_users() :: %{atom => pid()}
def get_users() do
GenServer.call(:IG, :get_users)
end
def login(account \\ nil) do
GenServer.call(:IG, {:login, account})
end
## Callbacks
def handle_call(:get_users, _from, state) do
{:reply, state.users, state}
end
def handle_call({:login, nil}, _from, state) do
user = state.users
|> Map.keys
|> List.first
user_data = login_user(Map.get(state.users, user, nil))
{:reply, user_data, state}
end
def handle_call({:login, user}, _from, state) do
user_data = login_user(Map.get(state.users, user, nil))
{:reply, user_data, state}
end
## Private functions
@type credential ::
{:identifier, String.t()}
| {:password, String.t()}
| {:api_key, String.t()}
| {:demo, boolean()}
@spec init_account({atom(), [credential]}) :: {atom(), {:ok, pid()}}
defp init_account({user, credentials}) do
{:ok, pid} = Ig.User.start_link(credentials, [name: :"user-#{user}"])
{user, pid}
end
defp login_user(pid) do
Ig.User.login(pid)
end
end