Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/integration-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: trading-ig integration test

on:
schedule:
- cron: '25 2 * * 1-4'
- cron: '0 23 * * 1-4'
workflow_dispatch:

jobs:
Expand Down
16 changes: 9 additions & 7 deletions docs/source/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Connection

>>> from trading_ig.rest import IGService
>>> from trading_ig.config import config
>>> ig_service = IGService(config.username, config.password, config.api_key)
>>> ig_service = IGService(config.username, config.password, config.api_key, config.acc_number)
>>> ig = ig_service.create_session()
>>> ig

Expand Down Expand Up @@ -108,17 +108,19 @@ Assuming config as above

>>> from trading_ig import IGService, IGStreamService
>>> from trading_ig.config import config
>>> from trading_ig.lightstreamer import Subscription
>>> from lightstreamer.client import Subscription, SubscriptionListener, ItemUpdate

>>> def on_update(item):
>>> print("{UPDATE_TIME:<8} {stock_name:<19} Bid {BID:>5} Ask {OFFER:>5}".format(stock_name=item["name"], **item["values"]))
>>> class PriceListener(SubscriptionListener):
>>> def onItemUpdate(self, update: ItemUpdate):
>>> logger.info(f"{update.getItemName()} Bid: {update.getValue('BIDPRICE1')}, Offer: {update.getValue('ASKPRICE1')}")

>>> ig_service = IGService(config.username, config.password, config.api_key, config.acc_type, acc_number=config.acc_number)
>>> ig_stream_service = IGStreamService(ig_service)
>>> ig_stream_service.create_session()
>>> sub = Subscription(mode="MERGE", items=["L1:CS.D.GBPUSD.TODAY.IP"], fields=["UPDATE_TIME", "BID", "OFFER"])
>>> sub.addlistener(on_update)
>>> ig_stream_service.ls_client.subscribe(sub)
>>> sub = Subscription(mode="MERGE", items=[f"PRICE:{config.acc_number}:CS.D.GBPUSD.TODAY.IP"], fields=["BIDPRICE1", "ASKPRICE1"])
>>> sub.setDataAdapter("Pricing")
>>> sub.addListener(PriceListener())
>>> ig_stream_service.subscribe(sub)
>>> ig_stream_service.disconnect()


Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,17 @@ Issues = "https://github.com/ig-python/trading-ig/issues"

[dependency-groups]
dev = [
"ruff",
"pytest>=8,<9",
"responses>=0.25,<0.26",
"coveralls>=3,<4",
"sphinx",
"sphinx-rtd-theme",
"ruff==0.16.1",
]

[tool.uv.build-backend]
module-name = "trading_ig"
module-root = ""

[tool.ruff.lint]
ignore = ["B017", "B023", "BLE001", "TRY002" ]
5 changes: 3 additions & 2 deletions sample/all_nodes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from trading_ig.rest import IGService, ApiExceededException
from tenacity import Retrying, retry_if_exception_type, wait_exponential

from trading_ig.config import config
from tenacity import Retrying, wait_exponential, retry_if_exception_type
from trading_ig.rest import ApiExceededException, IGService

DEFAULT_RETRY = Retrying(
wait=wait_exponential(), retry=retry_if_exception_type(ApiExceededException)
Expand Down
6 changes: 3 additions & 3 deletions sample/rest.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"metadata": {},
"outputs": [],
"source": [
"from trading_ig.rest import IGService\n",
"from trading_ig.config import config\n",
"from trading_ig.rest import IGService\n",
"\n",
"service = IGService(\n",
" config.username,\n",
Expand Down Expand Up @@ -126,9 +126,9 @@
"metadata": {},
"outputs": [],
"source": [
"from datetime import datetime, timedelta\n",
"from datetime import datetime, timedelta, timezone\n",
"\n",
"to_date = datetime.now()\n",
"to_date = datetime.now(timezone.utc)\n",
"from_date = to_date - timedelta(days=7)\n",
"\n",
"service.fetch_transaction_history(from_date=from_date, to_date=to_date)"
Expand Down
15 changes: 7 additions & 8 deletions sample/rest_ig.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-

"""
IG Markets REST API sample with Python
2015 FemtoTrader
"""

from trading_ig import IGService
from trading_ig.config import config
import logging

# if you need to cache to DB your requests
from datetime import timedelta

import requests_cache

from trading_ig import IGService
from trading_ig.config import config

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

Expand Down Expand Up @@ -49,20 +48,20 @@ def main():
# ig_stream_service.create_session(version='3')

accounts = ig_service.fetch_accounts()
print("accounts:\n%s" % accounts)
print(f"accounts:\n{accounts}")

# account_info = ig_service.switch_account(config.acc_number, False)
# print(account_info)

# open_positions = ig_service.fetch_open_positions()
# print("open_positions:\n%s" % open_positions)

print("")
print()

# working_orders = ig_service.fetch_working_orders()
# print("working_orders:\n%s" % working_orders)

print("")
print()

# epic = 'CS.D.EURUSD.MINI.IP'
epic = "IX.D.ASX.IFM.IP" # US (SPY) - mini
Expand Down
5 changes: 3 additions & 2 deletions sample/sample_ticker.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import logging
import time

from sample.sample_utils import crypto_epics # fx_epics, index_epics, weekend_epics
from trading_ig import IGService, IGStreamService
from trading_ig.config import config
from trading_ig.streamer.manager import StreamingManager
from sample.sample_utils import crypto_epics # fx_epics, index_epics, weekend_epics


def main():
Expand All @@ -26,7 +27,7 @@ def main():
sm.start_tick_subscription(epic)
tickers.append(sm.ticker(epic))

for idx in range(0, 10):
for idx in range(10):
for ticker in tickers:
print(ticker)
time.sleep(0.5)
Expand Down
5 changes: 3 additions & 2 deletions sample/sample_ticker_rich.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import logging
import time

from sample.sample_utils import crypto_epics # fx_epics, index_epics, weekend_epics
from trading_ig import IGService, IGStreamService
from trading_ig.config import config
from trading_ig.streamer.manager import StreamingManager
from sample.sample_utils import crypto_epics # fx_epics, index_epics, weekend_epics

try:
from rich.table import Table
from rich.live import Live
from rich.table import Table
except ImportError:
print("Rich must be installed for this sample")

Expand Down
2 changes: 1 addition & 1 deletion sample/sample_utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
def wait_for_input():
input("{0:-^80}\n".format("HIT CR TO UNSUBSCRIBE AND DISCONNECT"))
input("{:-^80}\n".format("HIT CR TO UNSUBSCRIBE AND DISCONNECT"))


# sample weekend spreadbet epics
Expand Down
16 changes: 9 additions & 7 deletions sample/stream_ig.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import sys
#!/usr/bin/env python

import logging
from datetime import datetime
import sys
from datetime import datetime, timezone

from lightstreamer.client import (
ClientListener,
ItemUpdate,
Subscription,
SubscriptionListener,
ItemUpdate,
ClientListener,
)

from sample.sample_utils import crypto_epics, wait_for_input
from trading_ig import IGService, IGStreamService
from trading_ig.config import config
from sample.sample_utils import crypto_epics, wait_for_input

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -100,7 +102,7 @@ def ig_stream_sample():
class PriceListener(SubscriptionListener):
def onItemUpdate(self, update: ItemUpdate):
logger.info(
f"{datetime.fromtimestamp(int(update.getValue('TIMESTAMP')) / 1000).strftime('%Y-%m-%d %H:%M:%S')} "
f"{datetime.fromtimestamp(int(update.getValue('TIMESTAMP')) / 1000, tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S')} "
f"{update.getItemName()} "
f"Bid: {update.getValue('BIDPRICE1')}, "
f"Offer: {update.getValue('ASKPRICE1')}, "
Expand Down Expand Up @@ -164,7 +166,7 @@ def onUnsubscription(self):

class StatusListener(ClientListener):
def onStatusChange(self, status):
print(f"{datetime.now()}: ***** {status} *****")
print(f"{datetime.now(timezone.utc)}: ***** {status} *****")


if __name__ == "__main__":
Expand Down
10 changes: 6 additions & 4 deletions tests/retry_test.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from trading_ig.rest import IGService, ApiExceededException, TokenInvalidException
import responses
from responses import Response
import json

import pandas as pd
import responses
import tenacity
from responses import Response
from tenacity import Retrying
import pandas as pd

from trading_ig.rest import ApiExceededException, IGService, TokenInvalidException

RETRYABLE = (ApiExceededException, TokenInvalidException)

Expand Down
6 changes: 4 additions & 2 deletions tests/test_accounts.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from trading_ig.rest import IGService
import responses
import json

import pandas as pd
import responses

from trading_ig.rest import IGService

"""
unit tests for accounts methods
Expand Down
12 changes: 7 additions & 5 deletions tests/test_activities.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from trading_ig.rest import IGService
import responses
import json
import pandas as pd
from datetime import datetime, timedelta
import re
from datetime import datetime, timedelta, timezone

import pandas as pd
import responses

from trading_ig.rest import IGService


class TestActivities:
Expand Down Expand Up @@ -56,7 +58,7 @@ def test_activities_by_date(self):
)

ig_service = IGService("username", "password", "api_key", "DEMO")
to_date = datetime.now()
to_date = datetime.now(timezone.utc)
from_date = to_date - timedelta(days=7)
result = ig_service.fetch_account_activity_by_date(from_date, to_date)

Expand Down
6 changes: 4 additions & 2 deletions tests/test_dealing.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from trading_ig.rest import IGService
import responses
import json

import pandas as pd
import responses

from trading_ig.rest import IGService

"""
unit tests for dealing methods
Expand Down
14 changes: 8 additions & 6 deletions tests/test_historical_prices.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from trading_ig.rest import IGService
import responses
import datetime
import json
import re

import pandas as pd
import datetime
import pytest
import re
import responses

from trading_ig.rest import IGService

"""
unit tests for historical prices methods
Expand Down Expand Up @@ -125,7 +127,7 @@ def test_historical_prices_v3_num_points_bad_numpoints(self):
responses.GET,
"https://demo-api.ig.com/gateway/deal/prices/MT.D.GC.Month2.IP",
headers={"CST": "abc123", "X-SECURITY-TOKEN": "xyz987"},
json={"errorCode": "Unable to convert value=3.14159 to type= Integer int"}, # noqa
json={"errorCode": "Unable to convert value=3.14159 to type= Integer int"},
status=400,
)

Expand Down Expand Up @@ -418,7 +420,7 @@ def test_historical_prices_by_epic_and_num_points_bad_numpoints(self):
responses.GET,
"https://demo-api.ig.com/gateway/deal/prices/MT.D.GC.Month2.IP",
headers={"CST": "abc123", "X-SECURITY-TOKEN": "xyz987"},
json={"errorCode": "Unable to convert value=3.14159 to type= Integer int"}, # noqa
json={"errorCode": "Unable to convert value=3.14159 to type= Integer int"},
status=400,
)

Expand Down
10 changes: 6 additions & 4 deletions tests/test_historical_prices_flat.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from trading_ig.rest import IGService
import responses
import datetime
import json

import pandas as pd
import datetime
import pytest
import responses

from trading_ig.rest import IGService

"""
unit tests for historical prices methods with flat output formatting
Expand Down Expand Up @@ -130,7 +132,7 @@ def test_historical_prices_v3_num_points_bad_numpoints(self):
responses.GET,
"https://demo-api.ig.com/gateway/deal/prices/MT.D.GC.Month2.IP",
headers={"CST": "abc123", "X-SECURITY-TOKEN": "xyz987"},
json={"errorCode": "Unable to convert value=3.14159 to type= Integer int"}, # noqa
json={"errorCode": "Unable to convert value=3.14159 to type= Integer int"},
status=400,
)

Expand Down
Loading