├── .gitignore ├── setup.cfg ├── .idea ├── .gitignore ├── vcs.xml ├── encodings.xml ├── modules.xml ├── misc.xml ├── ig-markets-api-python-library-master.iml └── inspectionProfiles │ └── Project_Default.xml ├── .DS_Store ├── requirements-test.txt ├── trading_ig ├── ._utils.py ├── ._config.py ├── ._stream.py ├── ._version.py ├── .___init__.py ├── ._lightstreamer.py ├── __pycache__ │ ├── rest.cpython-36.pyc │ ├── rest.cpython-37.pyc │ ├── rest.cpython-39.pyc │ ├── utils.cpython-36.pyc │ ├── utils.cpython-37.pyc │ ├── utils.cpython-39.pyc │ ├── __init__.cpython-36.pyc │ ├── __init__.cpython-37.pyc │ ├── __init__.cpython-39.pyc │ ├── config.cpython-36.pyc │ ├── config.cpython-37.pyc │ ├── config.cpython-39.pyc │ ├── stream.cpython-36.pyc │ ├── stream.cpython-37.pyc │ ├── stream.cpython-39.pyc │ ├── lightstreamer.cpython-36.pyc │ ├── lightstreamer.cpython-37.pyc │ └── lightstreamer.cpython-39.pyc ├── __init__.py ├── config.py ├── stream.py └── utils.py ├── tests ├── ._test_ig_service.py ├── data │ ├── switch.json │ ├── session.json │ ├── accounts.json │ ├── accounts_balances.json │ ├── workingorders.json │ ├── historic_prices_v1.json │ ├── historic_prices_dates.json │ ├── historic_prices_v2.json │ ├── historic_prices.json │ └── historic_prices_num_points.json ├── youtube_tut │ ├── order_lookup.py │ ├── deleting_orders.py │ ├── temp_algo_controller.py │ ├── order_generation.py │ ├── closing_position.py │ ├── position_generation.py │ └── lookup_position.py ├── test_utils.py ├── test_accounts.py ├── test_dealing.py ├── setup.py └── test_ig_service.py ├── requirements.txt ├── get_data ├── __pycache__ │ ├── get_market_data.cpython-37.pyc │ └── get_market_data.cpython-39.pyc └── get_market_data.py ├── sending_orders ├── __pycache__ │ ├── order_management.cpython-37.pyc │ └── order_management.cpython-39.pyc ├── rest_ig_sending_orders.py └── order_management.py ├── getting_realtime_data ├── __pycache__ │ ├── data_retrieval.cpython-37.pyc │ └── data_retrieval.cpython-39.pyc ├── stream_ig_getting_realtime_data.py └── data_retrieval.py ├── predefined_functions ├── __pycache__ │ ├── initialisation.cpython-37.pyc │ ├── initialisation.cpython-39.pyc │ ├── defined_functionality.cpython-37.pyc │ ├── defined_functionality.cpython-39.pyc │ └── algo_close_positons_in_profit.cpython-37.pyc ├── initialisation.py ├── algo_creating_working_orders_at_open_on_both_side_quick_functions.py ├── temp_algo_tut.py ├── algo_doing_simple_tasks.py ├── algo_minute_on_quotes.py ├── algo_close_positons_in_profit.py ├── algo_ten_minute.py └── algo_catch_trends_from_different_markets.py ├── management_of_position ├── __pycache__ │ ├── position_management.cpython-37.pyc │ └── position_management.cpython-39.pyc └── position_management.py ├── trading_ig_config.py ├── runAlgo_single_instrument └── controller_functionality.py ├── tox.ini ├── runAlgo_StopLoss └── controller_functionality.py ├── runAlgo_Take_Opposite_position_over_sharp_price_changes ├── controller_functionality.py └── controller_functionality_historical_data.py ├── runAlgo_Create_Working_Orders_on_both_side_at_opening ├── controller_functionality_quick_functions.py └── controller_functionality.py ├── algo_arbitrage_eur_gbp └── controller_arbitrage_0.py ├── .github └── FUNDING.yml ├── positions_on_both_sides └── controller_functionality.py ├── LICENSE ├── README.md ├── getting_historical_data ├── data_retrieval_historical.py └── rest_ig_get_historical_data.py ├── sample ├── stream_ig.py ├── stream_stock_list_demo.py └── rest_ig.py ├── getting_instrument_based_data ├── update_instrument_data_IG.py └── rest_ig_get_instrument_data.py ├── setup.py ├── Linked_to_biggest_previous_day_difference_in_price ├── adding_all_realtime_IG_data_to_file.py └── adding_realtime_IG_data_to_file.py └── Data └── CFDs └── instrument_details_SECTORS.csv /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal = 1 3 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/.DS_Store -------------------------------------------------------------------------------- /requirements-test.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | nose 3 | pandas 4 | requests 5 | requests-cache 6 | munch 7 | six 8 | -------------------------------------------------------------------------------- /trading_ig/._utils.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/._utils.py -------------------------------------------------------------------------------- /trading_ig/._config.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/._config.py -------------------------------------------------------------------------------- /trading_ig/._stream.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/._stream.py -------------------------------------------------------------------------------- /trading_ig/._version.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/._version.py -------------------------------------------------------------------------------- /tests/._test_ig_service.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/tests/._test_ig_service.py -------------------------------------------------------------------------------- /trading_ig/.___init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/.___init__.py -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | munch==2.5.0 2 | pycryptodome==3.9.8 3 | requests==2.24.0 4 | requests-cache==0.5.2 5 | six==1.15.0 6 | pandas==1.0.5 7 | -------------------------------------------------------------------------------- /trading_ig/._lightstreamer.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/._lightstreamer.py -------------------------------------------------------------------------------- /trading_ig/__pycache__/rest.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/rest.cpython-36.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/rest.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/rest.cpython-37.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/rest.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/rest.cpython-39.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/utils.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/utils.cpython-36.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/utils.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/utils.cpython-37.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/utils.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/utils.cpython-39.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/config.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/config.cpython-36.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/config.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/config.cpython-37.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/config.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/config.cpython-39.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/stream.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/stream.cpython-36.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/stream.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/stream.cpython-37.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/stream.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/stream.cpython-39.pyc -------------------------------------------------------------------------------- /get_data/__pycache__/get_market_data.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/get_data/__pycache__/get_market_data.cpython-37.pyc -------------------------------------------------------------------------------- /get_data/__pycache__/get_market_data.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/get_data/__pycache__/get_market_data.cpython-39.pyc -------------------------------------------------------------------------------- /tests/data/switch.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingStopsEnabled": true, 3 | "dealingEnabled": true, 4 | "hasActiveDemoAccounts": true, 5 | "hasActiveLiveAccounts": true 6 | } -------------------------------------------------------------------------------- /trading_ig/__pycache__/lightstreamer.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/lightstreamer.cpython-36.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/lightstreamer.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/lightstreamer.cpython-37.pyc -------------------------------------------------------------------------------- /trading_ig/__pycache__/lightstreamer.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/trading_ig/__pycache__/lightstreamer.cpython-39.pyc -------------------------------------------------------------------------------- /sending_orders/__pycache__/order_management.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/sending_orders/__pycache__/order_management.cpython-37.pyc -------------------------------------------------------------------------------- /sending_orders/__pycache__/order_management.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/sending_orders/__pycache__/order_management.cpython-39.pyc -------------------------------------------------------------------------------- /getting_realtime_data/__pycache__/data_retrieval.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/getting_realtime_data/__pycache__/data_retrieval.cpython-37.pyc -------------------------------------------------------------------------------- /getting_realtime_data/__pycache__/data_retrieval.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/getting_realtime_data/__pycache__/data_retrieval.cpython-39.pyc -------------------------------------------------------------------------------- /predefined_functions/__pycache__/initialisation.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/predefined_functions/__pycache__/initialisation.cpython-37.pyc -------------------------------------------------------------------------------- /predefined_functions/__pycache__/initialisation.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/predefined_functions/__pycache__/initialisation.cpython-39.pyc -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /management_of_position/__pycache__/position_management.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/management_of_position/__pycache__/position_management.cpython-37.pyc -------------------------------------------------------------------------------- /management_of_position/__pycache__/position_management.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/management_of_position/__pycache__/position_management.cpython-39.pyc -------------------------------------------------------------------------------- /predefined_functions/__pycache__/defined_functionality.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/predefined_functions/__pycache__/defined_functionality.cpython-37.pyc -------------------------------------------------------------------------------- /predefined_functions/__pycache__/defined_functionality.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/predefined_functions/__pycache__/defined_functionality.cpython-39.pyc -------------------------------------------------------------------------------- /tests/youtube_tut/order_lookup.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.defined_functionality import Defined_Functionality 2 | 3 | 4 | df = Defined_Functionality() 5 | 6 | orders = df.get_working_orders() 7 | 8 | print("stop") 9 | -------------------------------------------------------------------------------- /predefined_functions/__pycache__/algo_close_positons_in_profit.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g-make-it/IG_Trading_Algo_Scripts_Python/HEAD/predefined_functions/__pycache__/algo_close_positons_in_profit.cpython-37.pyc -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/data/session.json: -------------------------------------------------------------------------------- 1 | { 2 | "clientId": "100112233", 3 | "accountId": "ABC123", 4 | "timezoneOffset": 1, 5 | "locale": "en_GB", 6 | "currency": "GBP", 7 | "lightstreamerEndpoint": "https://demo-apd.marketdatasystems.com" 8 | } -------------------------------------------------------------------------------- /tests/youtube_tut/deleting_orders.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.defined_functionality import Defined_Functionality 2 | 3 | 4 | df = Defined_Functionality() 5 | 6 | orders = df.get_working_orders() 7 | 8 | df.cancel_orders_by_epic("IX.D.NASDAQ.CASH.IP") 9 | 10 | print("stop") 11 | -------------------------------------------------------------------------------- /trading_ig_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | 4 | 5 | class config(object): 6 | username = "YOUR_USERNAME" 7 | password = "YOUR_PASSWORD" 8 | api_key = "YOUR_API_KEY" 9 | acc_type = "DEMO" # LIVE / DEMO 10 | acc_number = "ABC123" 11 | -------------------------------------------------------------------------------- /tests/youtube_tut/temp_algo_controller.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.temp_algo_tut import Algo0 2 | 3 | 4 | class Controller_Functionality: 5 | 6 | def run(self): 7 | algo = Algo0() 8 | algo.run() 9 | 10 | 11 | if __name__ == '__main__': 12 | Controller_Functionality().run() -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | -------------------------------------------------------------------------------- /runAlgo_single_instrument/controller_functionality.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.algo_creating_working_orders_for_only_one_instrument import Algo0 2 | 3 | class Controller_Functionality: 4 | 5 | 6 | def run(self): 7 | algo = Algo0() 8 | algo.run() 9 | 10 | 11 | 12 | 13 | 14 | 15 | if __name__ == '__main__': 16 | Controller_Functionality().run() -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (http://tox.testrun.org/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py27, py33 8 | 9 | [testenv] 10 | commands = nosetests -s -v 11 | deps = 12 | nose 13 | -------------------------------------------------------------------------------- /tests/youtube_tut/order_generation.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.defined_functionality import Defined_Functionality 2 | 3 | 4 | df = Defined_Functionality() 5 | 6 | order = df.create_working_order(epic="IX.D.NASDAQ.CASH.IP", direction="BUY",size=1, force_open=True) 7 | # if you have force_open == True = limits for your orders will not work - and it will throw you an error - order being rejected 8 | print("stop") 9 | -------------------------------------------------------------------------------- /tests/youtube_tut/closing_position.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.defined_functionality import Defined_Functionality 2 | 3 | 4 | df = Defined_Functionality() 5 | 6 | 7 | position = df.create_open_position(epic="IX.D.NASDAQ.CASH.IP", direction="BUY",size=1, force_open=True, guaranteed_stop=False, min_limit_stop=False) 8 | positions = df.get_open_positions() 9 | print("stop") 10 | output = df.close_position(position=positions[0]) 11 | print("stop") 12 | -------------------------------------------------------------------------------- /runAlgo_StopLoss/controller_functionality.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.initialisation import Initialisation 2 | from predefined_functions.algo_close_positons_in_profit import Algo0 3 | 4 | class Controller_Functionality: 5 | # def __init__(self): 6 | # intial = Initialisation() 7 | # self.initial = intial.initialise_connection() 8 | 9 | 10 | def run(self): 11 | algo = Algo0() 12 | algo.run() 13 | 14 | 15 | 16 | 17 | 18 | 19 | if __name__ == '__main__': 20 | Controller_Functionality().run() -------------------------------------------------------------------------------- /tests/youtube_tut/position_generation.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.defined_functionality import Defined_Functionality 2 | 3 | 4 | df = Defined_Functionality() 5 | 6 | # order = df.create_open_position(epic="IX.D.NASDAQ.CASH.IP", direction="BUY",size=1, force_open=True) 7 | order = df.create_open_position(epic="IX.D.NASDAQ.CASH.IP", direction="BUY",size=1, force_open=True, guaranteed_stop=False, min_limit_stop=False) 8 | # if you have force_open == True = limits for your orders will not work - and it will throw you an error - order being rejected 9 | print("stop") 10 | -------------------------------------------------------------------------------- /runAlgo_Take_Opposite_position_over_sharp_price_changes/controller_functionality.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.initialisation import Initialisation 2 | from predefined_functions.algo_opposing_position_on_sharp_price_changes import Algo0 3 | 4 | class Controller_Functionality: 5 | # def __init__(self): 6 | # intial = Initialisation() 7 | # self.initial = intial.initialise_connection() 8 | 9 | 10 | def run(self): 11 | algo = Algo0() 12 | algo.run() 13 | 14 | 15 | 16 | 17 | 18 | 19 | if __name__ == '__main__': 20 | Controller_Functionality().run() -------------------------------------------------------------------------------- /tests/test_utils.py: -------------------------------------------------------------------------------- 1 | from trading_ig.utils import conv_datetime 2 | 3 | """ 4 | Unit tests for utils module 5 | """ 6 | 7 | 8 | class TestUtils: 9 | 10 | def test_conv_datetime_format_1(self): 11 | result = conv_datetime('2020/03/01', 1) 12 | assert result == '2020:03:01-00:00:00' 13 | 14 | def test_conv_datetime_format_2(self): 15 | result = conv_datetime('2020/03/01', 2) 16 | assert result == '2020/03/01 00:00:00' 17 | 18 | def test_conv_datetime_format_3(self): 19 | result = conv_datetime('2020/03/01', 3) 20 | assert result == '2020/03/01 00:00:00' 21 | -------------------------------------------------------------------------------- /.idea/ig-markets-api-python-library-master.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | -------------------------------------------------------------------------------- /runAlgo_Create_Working_Orders_on_both_side_at_opening/controller_functionality_quick_functions.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.initialisation import Initialisation 2 | from predefined_functions.algo_creating_working_orders_at_open_on_both_side_quick_functions import Algo0 3 | 4 | class Controller_Functionality: 5 | # def __init__(self): 6 | # intial = Initialisation() 7 | # self.initial = intial.initialise_connection() 8 | 9 | 10 | def run(self): 11 | algo = Algo0() 12 | algo.run() 13 | 14 | 15 | 16 | 17 | 18 | 19 | if __name__ == '__main__': 20 | Controller_Functionality().run() -------------------------------------------------------------------------------- /runAlgo_Take_Opposite_position_over_sharp_price_changes/controller_functionality_historical_data.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.initialisation import Initialisation 2 | from predefined_functions.algo_opposing_position_on_sharp_price_changes_based_on_historical_data import Algo0 3 | 4 | class Controller_Functionality: 5 | # def __init__(self): 6 | # intial = Initialisation() 7 | # self.initial = intial.initialise_connection() 8 | 9 | 10 | def run(self): 11 | algo = Algo0() 12 | algo.run() 13 | 14 | 15 | 16 | 17 | 18 | 19 | if __name__ == '__main__': 20 | Controller_Functionality().run() -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /algo_arbitrage_eur_gbp/controller_arbitrage_0.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.initialisation import Initialisation 2 | # from algo_arbitrage.trianglar_arbitrage_spreadbetting import Algo0 3 | from algo_arbitrage_eur_gbp.trianglar_arbitrage_spreadbetting_exiting_out_incrementally import Algo0 4 | 5 | class Controller_Functionality: 6 | # def __init__(self): 7 | # intial = Initialisation() 8 | # self.initial = intial.initialise_connection() 9 | 10 | 11 | def run(self): 12 | EURGBP = "CS.D.EURGBP.TODAY.IP" 13 | GBPEUR = "CS.D.GBPEUR.TODAY.IP" 14 | algo = Algo0(EURGBP=EURGBP, GBPEUR=GBPEUR) 15 | algo.run() 16 | 17 | 18 | 19 | 20 | 21 | 22 | if __name__ == '__main__': 23 | Controller_Functionality().run() -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: ['https://www.paypal.com/donate?hosted_button_id=WAJRVR3TBB4FN'] 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | -------------------------------------------------------------------------------- /tests/youtube_tut/lookup_position.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.defined_functionality import Defined_Functionality 2 | import time 3 | 4 | 5 | df = Defined_Functionality() 6 | 7 | # # order = df.create_open_position(epic="IX.D.NASDAQ.CASH.IP", direction="BUY",size=1, force_open=True) 8 | # order = df.create_open_position(epic="IX.D.NASDAQ.CASH.IP", direction="BUY",size=1, force_open=True, guaranteed_stop=False, min_limit_stop=False) 9 | # # if you have force_open == True = limits for your orders will not work - and it will throw you an error - order being rejected 10 | # 11 | # print("stop") 12 | 13 | positions_list = df.get_open_positions() 14 | 15 | print("stop") 16 | 17 | 18 | # while(True): 19 | # positions_list = df.get_open_positions() 20 | # print((positions_list[0])["position"]["openLevel"] - (positions_list[0])["market"]["offer"]) 21 | # time.sleep() -------------------------------------------------------------------------------- /trading_ig/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | IG Markets API Library for Python 6 | https://github.com/ig-python/ig-markets-api-python-library/ 7 | by Femto Trader - https://github.com/femtotrader 8 | """ 9 | 10 | from __future__ import absolute_import, division, print_function 11 | 12 | 13 | from .version import ( 14 | __author__, 15 | __copyright__, 16 | __credits__, 17 | __license__, 18 | __version__, 19 | __maintainer__, 20 | __author_email__, 21 | __status__, 22 | __url__, 23 | ) 24 | 25 | from .rest import IGService 26 | from .stream import IGStreamService 27 | 28 | __all__ = [ 29 | "IGService", 30 | "IGStreamService", 31 | "__author__", 32 | "__copyright__", 33 | "__credits__", 34 | "__license__", 35 | "__version__", 36 | "__maintainer__", 37 | "__author_email__", 38 | "__status__", 39 | "__url__", 40 | ] 41 | -------------------------------------------------------------------------------- /runAlgo_Create_Working_Orders_on_both_side_at_opening/controller_functionality.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.initialisation import Initialisation 2 | from predefined_functions.algo_creating_working_orders_at_open_on_both_side import Algo0 3 | 4 | class Controller_Functionality: 5 | # def __init__(self): 6 | # intial = Initialisation() 7 | # self.initial = intial.initialise_connection() 8 | 9 | 10 | def run(self): 11 | algo = Algo0() 12 | algo.run() 13 | 14 | 15 | 16 | 17 | 18 | 19 | if __name__ == '__main__': 20 | # run these program independently: 21 | # runAlgoStopLoss: - risk management 22 | # runAlgo_Create_Working_Orders_on_both_side_at_opening.controller_functionality_quick_function: make's sure all orders are balanced incase the program below take too long 23 | # and this one - creates the orders and works out the signal and instruments that we create orders for 24 | Controller_Functionality().run() -------------------------------------------------------------------------------- /positions_on_both_sides/controller_functionality.py: -------------------------------------------------------------------------------- 1 | # from predefined_functions.defined_functionality import Defined_Functionality 2 | from predefined_functions.initialisation import Initialisation 3 | # from predefined_functions.algo_ten_minute import Algo0 -- old one 4 | # from predefined_functions.algo_minute_on_quotes import Algo0 -- old one 5 | from predefined_functions.algo_positions_on_both_sides import Algo0 6 | # from predefined_functions.algo_catch_trends_from_different_markets import Algo0 7 | # from predefined_functions.algo_arbitration_between_two_instruments import Algo0 8 | 9 | class Controller_Functionality: 10 | def __init__(self): 11 | intial = Initialisation() 12 | self.initial = intial.initialise_connection() 13 | 14 | 15 | def run(self): 16 | algo = Algo0() 17 | algo.run() 18 | pass 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | if __name__ == '__main__': 30 | 31 | Controller_Functionality().run() -------------------------------------------------------------------------------- /tests/data/accounts.json: -------------------------------------------------------------------------------- 1 | { 2 | "accountType": "SPREADBET", 3 | "accountInfo": { 4 | "balance": 1000.00, 5 | "deposit": 500.00, 6 | "profitLoss": 500.00, 7 | "available": 1000.00 8 | }, 9 | "currencyIsoCode": "GBP", 10 | "currencySymbol": "£", 11 | "currentAccountId": "ABC123", 12 | "lightstreamerEndpoint": "https://demo-apd.marketdatasystems.com", 13 | "accounts": [ 14 | { 15 | "accountId": "ABC123", 16 | "accountName": "Demo-SpreadBet", 17 | "preferred": true, 18 | "accountType": "SPREADBET" 19 | }, 20 | { 21 | "accountId": "XYZ987", 22 | "accountName": "Demo-cfd", 23 | "preferred": false, 24 | "accountType": "CFD" 25 | } 26 | ], 27 | "clientId": "20007685858", 28 | "timezoneOffset": 0, 29 | "hasActiveDemoAccounts": true, 30 | "hasActiveLiveAccounts": true, 31 | "trailingStopsEnabled": true, 32 | "reroutingEnvironment": null, 33 | "dealingEnabled": true 34 | } -------------------------------------------------------------------------------- /tests/data/accounts_balances.json: -------------------------------------------------------------------------------- 1 | { 2 | "accounts": [ 3 | { 4 | "accountId": "XYZ987", 5 | "accountName": "Demo-SpreadBet", 6 | "accountAlias": null, 7 | "status": "ENABLED", 8 | "accountType": "SPREADBET", 9 | "preferred": false, 10 | "balance": { 11 | "balance": 1000.00, 12 | "deposit": 500.00, 13 | "profitLoss": 500.00, 14 | "available": 1000.00 15 | }, 16 | "currency": "GBP", 17 | "canTransferFrom": true, 18 | "canTransferTo": true 19 | }, 20 | { 21 | "accountId": "ABC123", 22 | "accountName": "Demo-cfd", 23 | "accountAlias": null, 24 | "status": "ENABLED", 25 | "accountType": "CFD", 26 | "preferred": true, 27 | "balance": null, 28 | "currency": "GBP", 29 | "canTransferFrom": true, 30 | "canTransferTo": true 31 | } 32 | ] 33 | } -------------------------------------------------------------------------------- /tests/test_accounts.py: -------------------------------------------------------------------------------- 1 | from trading_ig.rest import IGService 2 | import responses 3 | import json 4 | import pandas as pd 5 | 6 | """ 7 | unit tests for accounts methods 8 | """ 9 | 10 | 11 | class TestAccounts: 12 | 13 | # fetch_accounts 14 | 15 | @responses.activate 16 | def test_fetch_accounts_happy(self): 17 | 18 | with open('tests/data/accounts_balances.json', 'r') as file: 19 | response_body = json.loads(file.read()) 20 | 21 | responses.add(responses.GET, 'https://demo-api.ig.com/gateway/deal/accounts', 22 | headers={'CST': 'abc123', 'X-SECURITY-TOKEN': 'xyz987'}, 23 | json=response_body, 24 | status=200) 25 | 26 | ig_service = IGService('username', 'password', 'api_key', 'DEMO') 27 | ig_service.crud_session.HEADERS["LOGGED_IN"] = {} 28 | result = ig_service.fetch_accounts() 29 | 30 | pd.set_option('display.max_columns', 13) 31 | print(result) 32 | 33 | assert isinstance(result, pd.DataFrame) 34 | assert result.iloc[0]['accountId'] == 'XYZ987' 35 | assert result.iloc[0]['balance'] == 1000.0 36 | assert result.iloc[1]['accountId'] == 'ABC123' 37 | assert pd.isna(result.iloc[1]['balance']) 38 | assert pd.isna(result.iloc[1]['deposit']) 39 | -------------------------------------------------------------------------------- /tests/test_dealing.py: -------------------------------------------------------------------------------- 1 | from trading_ig.rest import IGService 2 | import responses 3 | import json 4 | import pandas as pd 5 | 6 | """ 7 | unit tests for dealing methods 8 | """ 9 | 10 | 11 | class TestDealing: 12 | 13 | # login v1 14 | 15 | @responses.activate 16 | def test_workingorders_happy(self): 17 | 18 | with open('tests/data/workingorders.json', 'r') as file: 19 | response_body = json.loads(file.read()) 20 | 21 | responses.add(responses.GET, 22 | 'https://demo-api.ig.com/gateway/deal/workingorders', 23 | headers={'CST': 'abc123', 'X-SECURITY-TOKEN': 'xyz987'}, 24 | json=response_body, 25 | status=200) 26 | 27 | ig_service = IGService('username', 'password', 'api_key', 'DEMO') 28 | ig_service.crud_session.HEADERS["LOGGED_IN"] = {} 29 | result = ig_service.fetch_working_orders() 30 | 31 | pd.set_option('display.max_columns', 50) 32 | print(result) 33 | 34 | assert isinstance(result, pd.DataFrame) 35 | assert result.iloc[0]['instrumentName'] == 'Spot Gold' 36 | assert result.iloc[0]['exchangeId'] == 'FX_C_GCSI_ST' 37 | assert result.iloc[0]['marketStatus'] == 'EDITS_ONLY' 38 | assert result.iloc[0]['level'] == 2000.0 39 | assert result.iloc[0]['epic'] == 'CS.D.CFDGOLD.CFDGC.IP' 40 | assert result.iloc[0]['currencyCode'] == 'USD' 41 | -------------------------------------------------------------------------------- /trading_ig/config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | import os 5 | import logging 6 | 7 | ENV_VAR_ROOT = "IG_SERVICE" 8 | CONFIG_FILE_NAME = "trading_ig_config.py" 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | 13 | class ConfigEnvVar(object): 14 | def __init__(self, env_var_base): 15 | self.ENV_VAR_BASE = env_var_base 16 | 17 | def _env_var(self, key): 18 | return self.ENV_VAR_BASE + "_" + key.upper() 19 | 20 | def get(self, key, default_value=None): 21 | env_var = self._env_var(key) 22 | return os.environ.get(env_var, default_value) 23 | 24 | def __getattr__(self, key): 25 | env_var = self._env_var(key) 26 | try: 27 | return os.environ[env_var] 28 | except KeyError: 29 | raise Exception("Environment variable '%s' doesn't exist" % env_var) 30 | 31 | 32 | try: 33 | from trading_ig_config import config 34 | 35 | logger.info("import config from %s" % CONFIG_FILE_NAME) 36 | except Exception: 37 | logger.warning("can't import config from config file") 38 | try: 39 | config = ConfigEnvVar(ENV_VAR_ROOT) 40 | logger.info("import config from environment variables '%s_...'" % ENV_VAR_ROOT) 41 | except Exception: 42 | logger.warning("can't import config from environment variables") 43 | raise ( 44 | """Can't import config - you might create a '%s' filename or use 45 | environment variables such as '%s_...'""" 46 | % (CONFIG_FILE_NAME, ENV_VAR_ROOT) 47 | ) 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, femtotrader 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of ig-markets-stream-api-python-library nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /tests/data/workingorders.json: -------------------------------------------------------------------------------- 1 | { 2 | "workingOrders": [ 3 | { 4 | "workingOrderData": { 5 | "dealId": "ABCD1234", 6 | "direction": "BUY", 7 | "epic": "CS.D.CFDGOLD.CFDGC.IP", 8 | "size": 0.05, 9 | "level": 2000.00, 10 | "goodTill": "GTC", 11 | "createdDate": "2020/10/01 10:00:00:000", 12 | "controlledRisk": false, 13 | "trailingTriggerIncrement": null, 14 | "trailingTriggerDistance": null, 15 | "trailingStopDistance": null, 16 | "trailingStopIncrement": null, 17 | "requestType": "STOP_ORDER", 18 | "contingentStop": null, 19 | "currencyCode": "USD", 20 | "contingentLimit": null, 21 | "dma": false, 22 | "limitedRiskPremium": null 23 | }, 24 | "marketData": { 25 | "instrumentName": "Spot Gold", 26 | "exchangeId": "FX_C_GCSI_ST", 27 | "expiry": "-", 28 | "marketStatus": "EDITS_ONLY", 29 | "epic": "CS.D.CFDGOLD.CFDGC.IP", 30 | "instrumentType": "CURRENCIES", 31 | "lotSize": 100.0, 32 | "high": 1960.0, 33 | "low": 1920.0, 34 | "percentageChange": 0.0, 35 | "netChange": 0.0, 36 | "bid": 1950.00, 37 | "offer": 1951.00, 38 | "updateTime": "2020/10/01 09:00:00:000", 39 | "delayTime": 0, 40 | "streamingPricesAvailable": true, 41 | "scalingFactor": 1 42 | } 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /get_data/get_market_data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | IG Markets REST API sample with Python 6 | 2015 FemtoTrader 7 | """ 8 | 9 | from trading_ig import IGService 10 | from trading_ig.config import config 11 | import logging 12 | # format to 13 | # # from folder.file import class 14 | # from getting_instrument_based_data.navigate_tree import NavigateTree 15 | 16 | logger = logging.getLogger(__name__) 17 | logger.setLevel(logging.DEBUG) 18 | 19 | # if you need to cache to DB your requests 20 | from datetime import timedelta 21 | import requests_cache 22 | import time 23 | import os 24 | import json 25 | 26 | from predefined_functions.initialisation import Initialisation 27 | 28 | class Get_Market_Data(): 29 | 30 | def __init__(self): 31 | self.initial = Initialisation() 32 | self.initialise_connection() 33 | 34 | def initialise_connection(self): 35 | self.ig_service = self.initial.initialise_connection() 36 | self.ig_service.create_session() 37 | 38 | def get_node_to_node_data(self,node): 39 | while(True): 40 | try: 41 | map_dataframe = self.ig_service.fetch_sub_nodes_by_node(node=node) 42 | return map_dataframe 43 | except Exception as e: 44 | print(e) 45 | self.initialise_connection() 46 | # time.sleep(1) 47 | 48 | def get_details_about_epic(self, epic): 49 | try: 50 | map_of_data = self.ig_service.fetch_market_by_epic(epic) 51 | data_string = json.dumps(map_of_data) 52 | data = json.loads(data_string) 53 | 54 | return data 55 | except Exception as e: 56 | print(e) 57 | self.initialise_connection() 58 | # time.sleep(1) 59 | 60 | 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IG_Trading_Algo_Scripts_Python 2 | IG Trading Algos and Scripts in Python 3 | 4 | This project is a collection of my work over 2 years building IG Trading Algorithms + Scripts, and [Donations](https://www.paypal.com/donate?hosted_button_id=WAJRVR3TBB4FN) would be much appreciated. 5 | 6 | The Data Folder holds instrument data, raw and cleaned: 7 | .csv files are intended to be used for pandas dataframes 8 | 9 | The algorithms follow a mvc format each controller calls a algorithm to run (some have been commented out) 10 | 11 | Create a file holding your API keys and state its path in __predefined_functions -> initialisation.py__ 12 | 13 | Check the video for more details: 14 | 15 | 16 | 17 | [![Watch the video](https://img.youtube.com/vi/joTp_a2sE8c/0.jpg)](https://www.youtube.com/watch?v=joTp_a2sE8c) 18 | 19 | ## Update 20 | 21 | ---------------------------- 22 | [![Watch the video](https://img.youtube.com/vi/5sxsvN5bv2s/0.jpg)](https://www.youtube.com/watch?v=5sxsvN5bv2s) 23 | 24 | 25 | ## [Subscribe](https://www.youtube.com/channel/UCsQqV_wq5yPrw5YIpvwmjvQ) to my youtube channel to find similar content. 26 | ## [Donations](https://www.paypal.com/donate?hosted_button_id=WAJRVR3TBB4FN). 27 | 28 | ------------------------ 29 | 30 | ### Just a few more notes: 31 | 32 | The core scripts used in trading_IG (license in root folder) and some of the scripts in test and 33 | the config are from: https://github.com/ig-python/ig-markets-api-python-library 34 | 35 | **All the other scripts + algos have been developed by me.** 36 | 37 | This project has a number of different algorithms, some had interesting results and others not so: The most interesting of those, I’ve documented in my videos: 38 | 39 | https://www.youtube.com/watch?v=9i5Rvi8XLwE - Positions on opposite sides of a single instrument 40 | 41 | https://www.youtube.com/watch?v=VO9KsEVHeBk - Opposite orders on a single instrument - before the market opens 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /predefined_functions/initialisation.py: -------------------------------------------------------------------------------- 1 | from trading_ig import IGService 2 | from trading_ig.config import config 3 | import logging 4 | 5 | logger = logging.getLogger(__name__) 6 | logger.setLevel(logging.DEBUG) 7 | 8 | # if you need to cache to DB your requests 9 | from datetime import timedelta 10 | import requests_cache 11 | 12 | 13 | class Initialisation(): 14 | def __init__(self): 15 | logging.basicConfig(level=logging.INFO) 16 | 17 | 18 | self.counter = -1 19 | self.initialise_connection() 20 | 21 | def initialise_connection(self): 22 | 23 | key = self.increment_api_key() 24 | 25 | # expire_after = timedelta(hours=1) 26 | # session = requests_cache.CachedSession( 27 | # cache_name='cache', backend='sqlite', expire_after=expire_after 28 | # ) 29 | # set expire_after=None if you don't want cache expiration 30 | # set expire_after=0 if you don't want to cache queries 31 | 32 | # no cache 33 | ig_service = IGService( 34 | config.username, config.password, key, config.acc_type 35 | ) 36 | # if you want to globally cache queries 37 | # ig_service = IGService(config.username, config.password, config.api_key, config.acc_type, session) 38 | return ig_service 39 | # make sure once the object is received to the place were it is needed you createSession() to initialise the session 40 | 41 | def increment_api_key(self): 42 | key = "" 43 | while (True): 44 | try: 45 | self.counter += 1 46 | # has 12000 api keys 47 | fp = open("D:\Stock_Analysis\ig-markets-api-python-library-master\generate_api_keys\IG_api_keys_raw.txt") 48 | for i, line in enumerate(fp): 49 | if i == self.counter: 50 | key = line.split("\n")[0] 51 | fp.close() 52 | return key 53 | raise Exception("file has surpassed the last api key") 54 | except: 55 | fp.close() 56 | self.counter = -1 57 | -------------------------------------------------------------------------------- /trading_ig/stream.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import, division, print_function 5 | 6 | import sys 7 | import traceback 8 | import logging 9 | 10 | from .lightstreamer import LSClient 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | 15 | class IGStreamService(object): 16 | def __init__(self, ig_service): 17 | self.ig_service = ig_service 18 | self.ig_session = None 19 | self.ls_client = None 20 | 21 | def create_session(self, encryption=False): 22 | ig_session = self.ig_service.create_session(encryption=encryption) 23 | self.ig_session = ig_session 24 | return ig_session 25 | 26 | def connect(self, accountId): 27 | cst = self.ig_service.crud_session.CLIENT_TOKEN 28 | xsecuritytoken = self.ig_service.crud_session.SECURITY_TOKEN 29 | lightstreamerEndpoint = self.ig_session[u"lightstreamerEndpoint"] 30 | # clientId = self.ig_session[u'clientId'] 31 | ls_password = "CST-%s|XST-%s" % (cst, xsecuritytoken) 32 | 33 | # Establishing a new connection to Lightstreamer Server 34 | logger.info("Starting connection with %s" % lightstreamerEndpoint) 35 | # self.ls_client = LSClient("http://localhost:8080", "DEMO") 36 | # self.ls_client = LSClient("http://push.lightstreamer.com", "DEMO") 37 | self.ls_client = LSClient( 38 | lightstreamerEndpoint, adapter_set="", user=accountId, password=ls_password 39 | ) 40 | try: 41 | self.ls_client.connect() 42 | return 43 | except Exception: 44 | logger.error("Unable to connect to Lightstreamer Server") 45 | logger.error(traceback.format_exc()) 46 | sys.exit(1) 47 | 48 | def unsubscribe_all(self): 49 | # To avoid a RuntimeError: dictionary changed size during iteration 50 | subscriptions = self.ls_client._subscriptions.copy() 51 | for subcription_key in subscriptions: 52 | self.ls_client.unsubscribe(subcription_key) 53 | 54 | def disconnect(self): 55 | self.unsubscribe_all() 56 | self.ls_client.disconnect() 57 | -------------------------------------------------------------------------------- /getting_historical_data/data_retrieval_historical.py: -------------------------------------------------------------------------------- 1 | import time 2 | import sys 3 | import traceback 4 | import logging 5 | import math 6 | 7 | from trading_ig import (IGService, IGStreamService) 8 | from trading_ig.config import config 9 | from trading_ig.lightstreamer import Subscription 10 | from predefined_functions.initialisation import Initialisation 11 | 12 | class Data_Retrieval_Historical: 13 | def __init__(self): 14 | self.data_map = {} 15 | self.ig_service = None 16 | self.initial = Initialisation() 17 | self.initialise_connection() 18 | 19 | def initialise_connection(self): 20 | while(True): 21 | try: 22 | self.ig_service = self.initial.initialise_connection() 23 | self.ig_service.create_session() 24 | return 25 | except Exception as e: 26 | print(e) 27 | 28 | 29 | 30 | def get_historical_data_based_date_range(self, epic, resolution, start_date, end_date): 31 | # start_date="2020-04-24" 32 | # end_date = "2020-05-01" 33 | response = None 34 | while (True): 35 | try: 36 | response = self.ig_service.fetch_historical_prices_by_epic_and_date_range(epic=epic, resolution=resolution, start_date=start_date, end_date=end_date) 37 | break 38 | except Exception as e: 39 | # print(e, " there was not data available") 40 | if (str(e) == "error.public-api.exceeded-account-historical-data-allowance") or ( 41 | str(e) == "error.security.generic") or ( 42 | str(e) == "error.public-api.exceeded-api-key-allowance"): 43 | self.initialise_connection() 44 | continue 45 | 46 | return None 47 | 48 | # print(response) 49 | data_frame_of_prices = response["prices"] 50 | 51 | return data_frame_of_prices 52 | 53 | def get_historical_data_based_num_points(self, epic, resolution, num_points): 54 | response = None 55 | while (True): 56 | try: 57 | response = self.ig_service.fetch_historical_prices_by_epic_and_num_points( epic, resolution, num_points) 58 | break 59 | except Exception as e: 60 | # print(e, " there was not data available") 61 | if (str(e) == "error.public-api.exceeded-account-historical-data-allowance") or ( 62 | str(e) == "error.security.generic") or ( 63 | str(e) == "error.public-api.exceeded-api-key-allowance"): 64 | self.initialise_connection() 65 | continue 66 | 67 | return None 68 | 69 | # print(response) 70 | data_frame_of_prices = response["prices"] 71 | 72 | return data_frame_of_prices -------------------------------------------------------------------------------- /sample/stream_ig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | IG Markets Stream API sample with Python 6 | 2015 FemtoTrader 7 | """ 8 | 9 | import time 10 | import sys 11 | import traceback 12 | import logging 13 | 14 | from trading_ig import IGService, IGStreamService 15 | from trading_ig.config import config 16 | from trading_ig.lightstreamer import Subscription 17 | 18 | 19 | # A simple function acting as a Subscription listener 20 | def on_prices_update(item_update): 21 | # print("price: %s " % item_update) 22 | print( 23 | "{stock_name:<19}: Time {UPDATE_TIME:<8} - " 24 | "Bid {BID:>5} - Ask {OFFER:>5}".format( 25 | stock_name=item_update["name"], **item_update["values"] 26 | ) 27 | ) 28 | 29 | 30 | def on_account_update(balance_update): 31 | print("balance: %s " % balance_update) 32 | 33 | 34 | def main(): 35 | logging.basicConfig(level=logging.INFO) 36 | # logging.basicConfig(level=logging.DEBUG) 37 | 38 | ig_service = IGService( 39 | config.username, config.password, config.api_key, config.acc_type 40 | ) 41 | 42 | ig_stream_service = IGStreamService(ig_service) 43 | ig_session = ig_stream_service.create_session() 44 | # Ensure configured account is selected 45 | accounts = ig_session[u"accounts"] 46 | for account in accounts: 47 | if account[u"accountId"] == config.acc_number: 48 | accountId = account[u"accountId"] 49 | break 50 | else: 51 | print("Account not found: {0}".format(config.acc_number)) 52 | accountId = None 53 | ig_stream_service.connect(accountId) 54 | 55 | # Making a new Subscription in MERGE mode 56 | subscription_prices = Subscription( 57 | mode="MERGE", 58 | items=["L1:CS.D.GBPUSD.CFD.IP", "L1:CS.D.USDJPY.CFD.IP"], 59 | fields=["UPDATE_TIME", "BID", "OFFER", "CHANGE", "MARKET_STATE"], 60 | ) 61 | # adapter="QUOTE_ADAPTER") 62 | 63 | # Adding the "on_price_update" function to Subscription 64 | subscription_prices.addlistener(on_prices_update) 65 | 66 | # Registering the Subscription 67 | sub_key_prices = ig_stream_service.ls_client.subscribe(subscription_prices) 68 | 69 | # Making an other Subscription in MERGE mode 70 | subscription_account = Subscription( 71 | mode="MERGE", items=["ACCOUNT:" + accountId], fields=["AVAILABLE_CASH"], 72 | ) 73 | # #adapter="QUOTE_ADAPTER") 74 | 75 | # Adding the "on_balance_update" function to Subscription 76 | subscription_account.addlistener(on_account_update) 77 | 78 | # Registering the Subscription 79 | sub_key_account = ig_stream_service.ls_client.subscribe(subscription_account) 80 | 81 | input( 82 | "{0:-^80}\n".format( 83 | "HIT CR TO UNSUBSCRIBE AND DISCONNECT FROM \ 84 | LIGHTSTREAMER" 85 | ) 86 | ) 87 | 88 | # Disconnecting 89 | ig_stream_service.disconnect() 90 | 91 | 92 | if __name__ == "__main__": 93 | main() 94 | -------------------------------------------------------------------------------- /sample/stream_stock_list_demo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Copyright 2015 Weswit s.r.l. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import sys 18 | import traceback 19 | import logging 20 | from trading_ig.lightstreamer import LSClient, Subscription 21 | 22 | 23 | # A simple function acting as a Subscription listener 24 | def on_item_update(item_update): 25 | print( 26 | "{stock_name:<19}: Last{last_price:>6} - Time {time:<8} - " 27 | "Bid {bid:>5} - Ask {ask:>5}".format(**item_update["values"]) 28 | ) 29 | 30 | 31 | def main(): 32 | # logging.basicConfig(level=logging.DEBUG) 33 | logging.basicConfig(level=logging.INFO) 34 | 35 | # Establishing a new connection to Lightstreamer Server 36 | print("Starting connection") 37 | # lightstreamer_client = LSClient("http://localhost:8080", "DEMO") 38 | lightstreamer_client = LSClient("http://push.lightstreamer.com", "DEMO") 39 | try: 40 | lightstreamer_client.connect() 41 | except Exception as e: 42 | print("Unable to connect to Lightstreamer Server") 43 | print(traceback.format_exc()) 44 | print(e) 45 | sys.exit(1) 46 | 47 | # Making a new Subscription in MERGE mode 48 | subscription = Subscription( 49 | mode="MERGE", 50 | items=[ 51 | "item1", 52 | "item2", 53 | "item3", 54 | "item4", 55 | "item5", 56 | "item6", 57 | "item7", 58 | "item8", 59 | "item9", 60 | "item10", 61 | "item11", 62 | "item12", 63 | ], 64 | fields=["stock_name", "last_price", "time", "bid", "ask"], 65 | adapter="QUOTE_ADAPTER", 66 | ) 67 | 68 | # Adding the "on_item_update" function to Subscription 69 | subscription.addlistener(on_item_update) 70 | 71 | # Registering the Subscription 72 | sub_key = lightstreamer_client.subscribe(subscription) 73 | print(sub_key) 74 | 75 | input( 76 | "{0:-^80}\n".format( 77 | "HIT CR TO UNSUBSCRIBE AND DISCONNECT FROM \ 78 | LIGHTSTREAMER" 79 | ) 80 | ) 81 | 82 | # Unsubscribing from Lightstreamer by using the subscription key 83 | # lightstreamer_client.unsubscribe(sub_key) 84 | 85 | lightstreamer_client.unsubscribe() 86 | 87 | # Disconnecting 88 | lightstreamer_client.disconnect() 89 | 90 | 91 | if __name__ == "__main__": 92 | main() 93 | -------------------------------------------------------------------------------- /sample/rest_ig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | IG Markets REST API sample with Python 6 | 2015 FemtoTrader 7 | """ 8 | 9 | from trading_ig import IGService 10 | from trading_ig.config import config 11 | import logging 12 | 13 | logger = logging.getLogger(__name__) 14 | logger.setLevel(logging.DEBUG) 15 | 16 | # if you need to cache to DB your requests 17 | from datetime import timedelta 18 | import requests_cache 19 | 20 | 21 | def main(): 22 | logging.basicConfig(level=logging.DEBUG) 23 | 24 | expire_after = timedelta(hours=1) 25 | session = requests_cache.CachedSession( 26 | cache_name="cache", backend="sqlite", expire_after=expire_after 27 | ) 28 | # set expire_after=None if you don't want cache expiration 29 | # set expire_after=0 if you don't want to cache queries 30 | 31 | # config = IGServiceConfig() 32 | 33 | # no cache 34 | ig_service = IGService( 35 | config.username, config.password, config.api_key, config.acc_type 36 | ) 37 | 38 | # if you want to globally cache queries 39 | # ig_service = IGService(config.username, config.password, config.api_key, config.acc_type, session) 40 | 41 | ig_service.create_session() 42 | 43 | # accounts = ig_service.fetch_accounts() 44 | # print("accounts:\n%s" % accounts) 45 | 46 | # account_info = ig_service.switch_account(config.acc_number, False) 47 | # print(account_info) 48 | 49 | # open_positions = ig_service.fetch_open_positions() 50 | # print("open_positions:\n%s" % open_positions) 51 | 52 | print("") 53 | 54 | # working_orders = ig_service.fetch_working_orders() 55 | # print("working_orders:\n%s" % working_orders) 56 | 57 | print("") 58 | 59 | # epic = 'CS.D.EURUSD.MINI.IP' 60 | epic = "IX.D.ASX.IFM.IP" # US (SPY) - mini 61 | 62 | resolution = "D" 63 | # see from pandas.tseries.frequencies import to_offset 64 | # resolution = 'H' 65 | # resolution = '1Min' 66 | 67 | num_points = 10 68 | response = ig_service.fetch_historical_prices_by_epic_and_num_points( 69 | epic, resolution, num_points 70 | ) 71 | 72 | print(response) 73 | 74 | # Exception: error.public-api.exceeded-account-historical-data-allowance 75 | 76 | # if you want to cache this query 77 | # response = ig_service.fetch_historical_prices_by_epic_and_num_points(epic, resolution, num_points, session) 78 | 79 | # df_ask = response['prices']['ask'] 80 | # print("ask prices:\n%s" % df_ask) 81 | 82 | # (start_date, end_date) = ('2015-09-15', '2015-09-28') 83 | # response = ig_service.fetch_historical_prices_by_epic_and_date_range(epic, resolution, start_date, end_date) 84 | 85 | # if you want to cache this query 86 | # response = ig_service.fetch_historical_prices_by_epic_and_date_range(epic, resolution, start_date, end_date, session) 87 | # df_ask = response['prices']['ask'] 88 | # print("ask prices:\n%s" % df_ask) 89 | 90 | 91 | if __name__ == "__main__": 92 | main() 93 | -------------------------------------------------------------------------------- /getting_realtime_data/stream_ig_getting_realtime_data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | 4 | """ 5 | IG Markets Stream API sample with Python 6 | 2015 FemtoTrader 7 | """ 8 | 9 | import time 10 | import sys 11 | import traceback 12 | import logging 13 | 14 | from trading_ig import (IGService, IGStreamService) 15 | from trading_ig.config import config 16 | from trading_ig.lightstreamer import Subscription 17 | 18 | 19 | # A simple function acting as a Subscription listener 20 | def on_prices_update(item_update): 21 | # print("price: %s " % item_update) 22 | print("{stock_name:<19}: Time {UPDATE_TIME:<8} - " 23 | "Bid {BID:>5} - Ask {OFFER:>5}".format( 24 | stock_name=item_update["name"], **item_update["values"] 25 | )) 26 | 27 | 28 | def on_account_update(balance_update): 29 | print("balance: %s " % balance_update) 30 | 31 | 32 | def main(): 33 | logging.basicConfig(level=logging.INFO) 34 | # logging.basicConfig(level=logging.DEBUG) 35 | 36 | ig_service = IGService( 37 | config.username, config.password, config.api_key, config.acc_type 38 | ) 39 | 40 | ig_stream_service = IGStreamService(ig_service) 41 | ig_session = ig_stream_service.create_session() 42 | accountId = config.acc_number 43 | # Ensure configured account is selected 44 | # accounts = ig_session[u'accounts'] 45 | # for account in accounts: 46 | # if account[u'accountId'] == config.acc_number: 47 | # accountId = account[u'accountId'] 48 | # break 49 | # else: 50 | # print('Account not found: {0}'.format(config.acc_number)) 51 | # accountId = None 52 | ig_stream_service.connect(accountId) 53 | 54 | # Making a new Subscription in MERGE mode 55 | subscription_prices = Subscription( 56 | mode="MERGE", 57 | # make sure to put L1 in front of the instrument name 58 | items=["L1:CS.D.BITCOIN.TODAY.IP", "L1:CS.D.ETHUSD.TODAY.IP"], 59 | fields=["UPDATE_TIME", "BID", "OFFER", "CHANGE", "MARKET_STATE", "MID_OPEN", "HIGH", "LOW", "CHANGE", "CHANGE_PCT", "MARKET_DELAY"] 60 | ) 61 | # adapter="QUOTE_ADAPTER") 62 | 63 | # Adding the "on_price_update" function to Subscription 64 | subscription_prices.addlistener(on_prices_update) 65 | 66 | # Registering the Subscription 67 | sub_key_prices = ig_stream_service.ls_client.subscribe(subscription_prices) 68 | 69 | # Making an other Subscription in MERGE mode 70 | subscription_account = Subscription( 71 | mode="MERGE", 72 | items=['ACCOUNT:'+accountId], 73 | fields=["AVAILABLE_CASH"], 74 | ) 75 | # #adapter="QUOTE_ADAPTER") 76 | 77 | # Adding the "on_balance_update" function to Subscription 78 | subscription_account.addlistener(on_account_update) 79 | 80 | 81 | # Registering the Subscription 82 | sub_key_account = ig_stream_service.ls_client.subscribe( 83 | subscription_account 84 | ) 85 | 86 | input("{0:-^80}\n".format("HIT CR TO UNSUBSCRIBE AND DISCONNECT FROM \ 87 | LIGHTSTREAMER")) 88 | 89 | # Disconnecting 90 | ig_stream_service.disconnect() 91 | 92 | 93 | if __name__ == '__main__': 94 | main() 95 | -------------------------------------------------------------------------------- /trading_ig/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | import os 5 | import logging 6 | import traceback 7 | import six 8 | 9 | logger = logging.getLogger(__name__) 10 | 11 | try: 12 | import pandas as pd 13 | except ImportError: 14 | _HAS_PANDAS = False 15 | logger.info("Can't import pandas") 16 | else: 17 | _HAS_PANDAS = True 18 | 19 | try: 20 | from munch import munchify # noqa 21 | except ImportError: 22 | _HAS_MUNCH = False 23 | logger.info("Can't import munch") 24 | else: 25 | _HAS_MUNCH = True 26 | 27 | 28 | DATE_FORMATS = {1: "%Y:%m:%d-%H:%M:%S", 2: "%Y/%m/%d %H:%M:%S", 3: "%Y/%m/%d %H:%M:%S"} 29 | 30 | 31 | def conv_resol(resolution): 32 | """Returns a string for resolution (from a Pandas) 33 | """ 34 | if _HAS_PANDAS: 35 | from pandas.tseries.frequencies import to_offset 36 | 37 | d = { 38 | to_offset("1s"): "SECOND", 39 | to_offset("1Min"): "MINUTE", 40 | to_offset("2Min"): "MINUTE_2", 41 | to_offset("3Min"): "MINUTE_3", 42 | to_offset("5Min"): "MINUTE_5", 43 | to_offset("10Min"): "MINUTE_10", 44 | to_offset("15Min"): "MINUTE_15", 45 | to_offset("30Min"): "MINUTE_30", 46 | to_offset("1H"): "HOUR", 47 | to_offset("2H"): "HOUR_2", 48 | to_offset("3H"): "HOUR_3", 49 | to_offset("4H"): "HOUR_4", 50 | to_offset("D"): "DAY", 51 | to_offset("W"): "WEEK", 52 | to_offset("M"): "MONTH", 53 | } 54 | offset = to_offset(resolution) 55 | if offset in d: 56 | return d[offset] 57 | else: 58 | logger.error(traceback.format_exc()) 59 | logger.warning("conv_resol returns '%s'" % resolution) 60 | return resolution 61 | else: 62 | return resolution 63 | 64 | 65 | def conv_datetime(dt, version=2): 66 | """Converts dt to string like 67 | version 1 = 2014:12:15-00:00:00 68 | version 2 = 2014/12/15 00:00:00 69 | version 3 = 2014/12/15 00:00:00 70 | """ 71 | try: 72 | if isinstance(dt, six.string_types): 73 | if _HAS_PANDAS: 74 | dt = pd.to_datetime(dt) 75 | 76 | fmt = DATE_FORMATS[int(version)] 77 | return dt.strftime(fmt) 78 | except (ValueError, TypeError): 79 | logger.error(traceback.format_exc()) 80 | logger.warning("conv_datetime returns %s" % dt) 81 | return dt 82 | 83 | 84 | def conv_to_ms(td): 85 | """Converts td to integer number of milliseconds""" 86 | try: 87 | if isinstance(td, six.integer_types): 88 | return td 89 | else: 90 | return int(td.total_seconds() * 1000.0) 91 | except ValueError: 92 | logger.error(traceback.format_exc()) 93 | logger.warning("conv_to_ms returns '%s'" % td) 94 | return td 95 | 96 | 97 | def remove(cache): 98 | """Remove cache""" 99 | try: 100 | filename = "%s.sqlite" % cache 101 | print("remove %s" % filename) 102 | os.remove(filename) 103 | except Exception: 104 | pass 105 | -------------------------------------------------------------------------------- /tests/data/historic_prices_v1.json: -------------------------------------------------------------------------------- 1 | { 2 | "prices": [ 3 | { 4 | "snapshotTime": "2020:09:01-05:00:00", 5 | "openPrice": { 6 | "bid": 1992.7, 7 | "ask": 1993.3, 8 | "lastTraded": null 9 | }, 10 | "closePrice": { 11 | "bid": 1970.7, 12 | "ask": 1971.3, 13 | "lastTraded": null 14 | }, 15 | "highPrice": { 16 | "bid": 2000.4, 17 | "ask": 2001.0, 18 | "lastTraded": null 19 | }, 20 | "lowPrice": { 21 | "bid": 1965.5, 22 | "ask": 1966.1, 23 | "lastTraded": null 24 | }, 25 | "lastTradedVolume": 202326 26 | }, 27 | { 28 | "snapshotTime": "2020:09:02-05:00:00", 29 | "openPrice": { 30 | "bid": 1970.8, 31 | "ask": 1971.4, 32 | "lastTraded": null 33 | }, 34 | "closePrice": { 35 | "bid": 1951.3, 36 | "ask": 1951.9, 37 | "lastTraded": null 38 | }, 39 | "highPrice": { 40 | "bid": 1978.4, 41 | "ask": 1979.0, 42 | "lastTraded": null 43 | }, 44 | "lowPrice": { 45 | "bid": 1938.7, 46 | "ask": 1939.3, 47 | "lastTraded": null 48 | }, 49 | "lastTradedVolume": 214134 50 | }, 51 | { 52 | "snapshotTime": "2020:09:03-05:00:00", 53 | "openPrice": { 54 | "bid": 1951.4, 55 | "ask": 1952.0, 56 | "lastTraded": null 57 | }, 58 | "closePrice": { 59 | "bid": 1942.8, 60 | "ask": 1943.4, 61 | "lastTraded": null 62 | }, 63 | "highPrice": { 64 | "bid": 1952.5, 65 | "ask": 1953.1, 66 | "lastTraded": null 67 | }, 68 | "lowPrice": { 69 | "bid": 1927.0, 70 | "ask": 1927.6, 71 | "lastTraded": null 72 | }, 73 | "lastTradedVolume": 215716 74 | }, 75 | { 76 | "snapshotTime": "2020:09:04-05:00:00", 77 | "openPrice": { 78 | "bid": 1942.9, 79 | "ask": 1943.5, 80 | "lastTraded": null 81 | }, 82 | "closePrice": { 83 | "bid": 1940.9, 84 | "ask": 1940.9, 85 | "lastTraded": null 86 | }, 87 | "highPrice": { 88 | "bid": 1955.2, 89 | "ask": 1956.2, 90 | "lastTraded": null 91 | }, 92 | "lowPrice": { 93 | "bid": 1921.7, 94 | "ask": 1922.3, 95 | "lastTraded": null 96 | }, 97 | "lastTradedVolume": 167178 98 | } 99 | ], 100 | "instrumentType": "COMMODITIES", 101 | "allowance": { 102 | "remainingAllowance": 9986, 103 | "totalAllowance": 10000, 104 | "allowanceExpiry": 462679 105 | } 106 | } -------------------------------------------------------------------------------- /getting_instrument_based_data/update_instrument_data_IG.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | from trading_ig import IGService 5 | from trading_ig.config import config 6 | 7 | from datetime import timedelta 8 | import requests_cache 9 | import json 10 | import pandas as pd 11 | pd.options.mode.chained_assignment = None # default='warn' 12 | 13 | 14 | def main(): 15 | ig_service = login() 16 | 17 | get_data(ig_service) 18 | 19 | def login(): 20 | expire_after = timedelta(hours=1) 21 | session = requests_cache.CachedSession( 22 | cache_name='cache', backend='sqlite', expire_after=expire_after 23 | ) 24 | api_key = increment_api_key() 25 | 26 | # no cache 27 | ig_service = IGService( 28 | config.username, config.password, api_key, config.acc_type 29 | ) 30 | ig_service.create_session() 31 | 32 | return ig_service 33 | 34 | 35 | 36 | def get_data(ig_service): 37 | Instrument_Data = pd.read_csv("D:\Stock_Analysis\ig-markets-api-python-library-master\Data\SpreadBetting\instruments_new.csv") 38 | Instrument_Data.drop("Unnamed: 0", axis=1, inplace=True) 39 | 40 | for index in range(Instrument_Data.index.size): 41 | # save the data 42 | try: 43 | data = get_data_required(Instrument_Data, index, ig_service) 44 | # if data == None: 45 | # continue 46 | temp = data["instrument"].copy() 47 | temp.update(data["dealingRules"]) 48 | temp.update(data["snapshot"]) 49 | 50 | data = temp 51 | put_in_right_column(data=data, Instrument_Data=Instrument_Data, index=index) 52 | 53 | Instrument_Data.to_csv("D:\Stock_Analysis\ig-markets-api-python-library-master\Data\SpreadBetting\instruments_new_updated.csv") 54 | 55 | except Exception as e: 56 | print(e) 57 | 58 | 59 | print("finished") 60 | 61 | 62 | def get_data_required(Instrument_Data, index, ig_service): 63 | try: 64 | row = Instrument_Data.iloc[index] 65 | epic_id = row["epic"] 66 | # save data 67 | map_data = get_details_about_epic(ig_service, epic_id) 68 | data_string = json.dumps(map_data) 69 | data = json.loads(data_string) 70 | return data 71 | except Exception as e: 72 | print(e) 73 | return None 74 | 75 | 76 | def put_in_right_column(data, Instrument_Data, index): 77 | object_df = Instrument_Data.loc[index] 78 | for key in data.keys(): 79 | object_df[key] = data[key] 80 | Instrument_Data.loc[index] = object_df 81 | print("stop") 82 | 83 | 84 | def get_details_about_epic(ig_service, epic): 85 | while(True): 86 | try: 87 | map_of_data = ig_service.fetch_market_by_epic(epic) 88 | return map_of_data 89 | except Exception as e: 90 | print(e) 91 | login() 92 | 93 | 94 | def increment_api_key(): 95 | key = "" 96 | global counter 97 | flag = True 98 | while (flag): 99 | try: 100 | counter += 1 101 | fp = open("D:\Stock_Analysis\ig-markets-api-python-library-master\generate_api_keys\IG_api_keys_raw.txt") 102 | for i, line in enumerate(fp): 103 | if i == counter: 104 | key = line.split("\n")[0] 105 | flag = False 106 | break 107 | 108 | fp.close() 109 | except: 110 | counter = -1 111 | 112 | return key 113 | 114 | 115 | 116 | 117 | if __name__ == '__main__': 118 | main() 119 | -------------------------------------------------------------------------------- /tests/data/historic_prices_dates.json: -------------------------------------------------------------------------------- 1 | { 2 | "prices": [ 3 | { 4 | "snapshotTime": "2020/09/01 05:00:00", 5 | "snapshotTimeUTC": "2020-09-01T04:00:00", 6 | "openPrice": { 7 | "bid": 1992.7, 8 | "ask": 1993.3, 9 | "lastTraded": null 10 | }, 11 | "closePrice": { 12 | "bid": 1970.7, 13 | "ask": 1971.3, 14 | "lastTraded": null 15 | }, 16 | "highPrice": { 17 | "bid": 2000.4, 18 | "ask": 2001.0, 19 | "lastTraded": null 20 | }, 21 | "lowPrice": { 22 | "bid": 1965.5, 23 | "ask": 1966.1, 24 | "lastTraded": null 25 | }, 26 | "lastTradedVolume": 202326 27 | }, 28 | { 29 | "snapshotTime": "2020/09/02 05:00:00", 30 | "snapshotTimeUTC": "2020-09-02T04:00:00", 31 | "openPrice": { 32 | "bid": 1970.8, 33 | "ask": 1971.4, 34 | "lastTraded": null 35 | }, 36 | "closePrice": { 37 | "bid": 1951.3, 38 | "ask": 1951.9, 39 | "lastTraded": null 40 | }, 41 | "highPrice": { 42 | "bid": 1978.4, 43 | "ask": 1979.0, 44 | "lastTraded": null 45 | }, 46 | "lowPrice": { 47 | "bid": 1938.7, 48 | "ask": 1939.3, 49 | "lastTraded": null 50 | }, 51 | "lastTradedVolume": 214134 52 | }, 53 | { 54 | "snapshotTime": "2020/09/03 05:00:00", 55 | "snapshotTimeUTC": "2020-09-03T04:00:00", 56 | "openPrice": { 57 | "bid": 1951.4, 58 | "ask": 1952.0, 59 | "lastTraded": null 60 | }, 61 | "closePrice": { 62 | "bid": 1942.8, 63 | "ask": 1943.4, 64 | "lastTraded": null 65 | }, 66 | "highPrice": { 67 | "bid": 1952.5, 68 | "ask": 1953.1, 69 | "lastTraded": null 70 | }, 71 | "lowPrice": { 72 | "bid": 1927.0, 73 | "ask": 1927.6, 74 | "lastTraded": null 75 | }, 76 | "lastTradedVolume": 215716 77 | }, 78 | { 79 | "snapshotTime": "2020/09/04 05:00:00", 80 | "snapshotTimeUTC": "2020-09-04T04:00:00", 81 | "openPrice": { 82 | "bid": 1942.9, 83 | "ask": 1943.5, 84 | "lastTraded": null 85 | }, 86 | "closePrice": { 87 | "bid": 1940.9, 88 | "ask": 1940.9, 89 | "lastTraded": null 90 | }, 91 | "highPrice": { 92 | "bid": 1955.2, 93 | "ask": 1956.2, 94 | "lastTraded": null 95 | }, 96 | "lowPrice": { 97 | "bid": 1921.7, 98 | "ask": 1922.3, 99 | "lastTraded": null 100 | }, 101 | "lastTradedVolume": 167178 102 | } 103 | ], 104 | "instrumentType": "COMMODITIES", 105 | "metadata": { 106 | "allowance": { 107 | "remainingAllowance": 500, 108 | "totalAllowance": 10000, 109 | "allowanceExpiry": 50000 110 | }, 111 | "size": 4, 112 | "pageData": { 113 | "pageSize": 20, 114 | "pageNumber": 1, 115 | "totalPages": 1 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /predefined_functions/algo_creating_working_orders_at_open_on_both_side_quick_functions.py: -------------------------------------------------------------------------------- 1 | from trading_ig.config import config 2 | import logging 3 | 4 | logger = logging.getLogger(__name__) 5 | logger.setLevel(logging.DEBUG) 6 | 7 | # if you need to cache to DB your requests 8 | from datetime import timedelta 9 | import requests_cache 10 | from getting_realtime_data.data_retrieval import Data_Retrieval 11 | from sending_orders.order_management import Order_Management 12 | from management_of_position.position_management import Position_Management 13 | from predefined_functions.initialisation import Initialisation 14 | from get_data.get_market_data import Get_Market_Data 15 | import time 16 | from datetime import datetime, timedelta, date 17 | from predefined_functions.defined_functionality import Defined_Functionality 18 | import traceback 19 | import pandas as pd 20 | import sys 21 | import math 22 | 23 | # the newest one where you make market order base on price movements 5 or more and try to catch the trend 24 | 25 | class Algo0: 26 | def __init__(self): 27 | logging.basicConfig(level=logging.INFO) 28 | self.df = Defined_Functionality() 29 | 30 | 31 | 32 | 33 | def run(self): 34 | 35 | while(True): 36 | 37 | try: 38 | 39 | start_time = datetime.now() 40 | self.check_all_working_orders() 41 | end_time = datetime.now() - start_time 42 | print(end_time) 43 | 44 | except Exception as e: 45 | print(e, "traceback back in custom algo frame work") 46 | traceback.print_exc() 47 | 48 | def check_all_working_orders(self): 49 | # check if opening market has passed , if we have a position in it then close all other orders, or if only one of that order remains 50 | orders = self.df.get_working_orders() 51 | for epic in orders["epic"].unique(): 52 | self.checking_working_order_is_present_under_epic_and_amend_orders(epic=epic) 53 | 54 | 55 | 56 | def checking_working_order_is_present_under_epic_and_amend_orders(self, epic): 57 | # check there are two orders for each epic 58 | created_order = True 59 | while(True): 60 | orders = self.df.get_working_orders_by_epic(epic=epic) 61 | if orders.index.size == 2: 62 | directions = orders["direction"].to_list() 63 | if ("BUY" in directions and "SELL" in directions): 64 | data = self.df.get_market_data(epic=epic) 65 | 66 | if data == None: 67 | continue 68 | # market is still open 69 | map_of_time = data["instrument"]["openingHours"] 70 | if map_of_time == None: 71 | break 72 | single_time = map_of_time["marketTimes"][0]["openTime"] 73 | opening_market_time = datetime.strptime(single_time, '%H:%M').time() 74 | diff_in_time = datetime.combine(date.today(), opening_market_time) - datetime.now() 75 | 76 | # if the time is bigger than x second then we can still put orders in place 77 | total_seconds = diff_in_time.total_seconds() 78 | # -1 seconds 79 | if total_seconds < -(0.2): 80 | # delete the orders if any are pending 81 | break 82 | 83 | position = self.df.find_open_position_by_epic(epic=epic) 84 | if len(position) != 0: 85 | break 86 | 87 | print("market is not open yet and orders are in place nothing needs to be done yet") 88 | return created_order 89 | 90 | break 91 | 92 | print("delete orders") 93 | self.df.cancel_orders_by_epic(epic=epic) 94 | created_order = False 95 | 96 | return created_order 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Always prefer setuptools over distutils 5 | from setuptools import setup, find_packages 6 | from codecs import open # To use a consistent encoding 7 | from os import path 8 | import io 9 | 10 | NAME = "trading_ig" 11 | filename = "%s/version.py" % NAME 12 | with open(filename) as f: 13 | exec(f.read()) 14 | 15 | here = path.abspath(path.dirname(__file__)) 16 | 17 | 18 | def readme(): 19 | filename = path.join(here, "README.rst") 20 | with io.open(filename, "rt", encoding="UTF-8") as f: 21 | return f.read() 22 | 23 | 24 | setup( 25 | name=NAME, 26 | # Versions should comply with PEP440. For a discussion on single-sourcing 27 | # the version across setup.py and the project code, see 28 | # https://packaging.python.org/en/latest/development.html#single-sourcing-the-version 29 | # version='0.0.1', 30 | version=__version__, 31 | description="A lightweight wrapper for the IG Markets API written in Python", 32 | long_description=readme(), 33 | # The project's main homepage. 34 | url=__url__, 35 | # Author details 36 | author=__author__, 37 | author_email=__author_email__, 38 | # Choose your license 39 | license=__license__, 40 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 41 | classifiers=[ 42 | # How mature is this project? Common values are 43 | # 3 - Alpha 44 | # 4 - Beta 45 | # 5 - Production/Stable 46 | "Development Status :: 3 - Alpha", 47 | # Indicate who your project is intended for 48 | "Environment :: Console", 49 | # 'Topic :: Software Development :: Build Tools', 50 | "Intended Audience :: Science/Research", 51 | "Operating System :: OS Independent", 52 | # Specify the Python versions you support here. In particular, ensure 53 | # that you indicate whether you support Python 2, Python 3 or both. 54 | "Programming Language :: Cython", 55 | "Programming Language :: Python", 56 | "Programming Language :: Python :: 3.6", 57 | "Programming Language :: Python :: 3.7", 58 | "Programming Language :: Python :: 3.8", 59 | "Topic :: Scientific/Engineering", 60 | # Pick your license as you wish (should match "license" above) 61 | "License :: OSI Approved :: BSD License", 62 | ], 63 | python_requires='>=3.6', 64 | # What does your project relate to? 65 | keywords="trading, spread betting, CFDs", 66 | # You can just specify the packages manually here if your project is 67 | # simple. Or you can use find_packages(). 68 | packages=find_packages(exclude=["contrib", "docs", "tests*"]), 69 | # List run-time dependencies here. These will be installed by pip when your 70 | # project is installed. For an analysis of "install_requires" vs pip's 71 | # requirements files see: 72 | # https://packaging.python.org/en/latest/technical.html#install-requires-vs-requirements-files 73 | install_requires=[ 74 | "munch==2.5.0", 75 | "pycryptodome==3.9.8", 76 | "requests==2.24.0", 77 | "requests-cache==0.5.2", 78 | "six==1.15.0", 79 | "pandas==1.0.5", 80 | ], # bunch->lunch->infi.bunch->munch 81 | # List additional groups of dependencies here (e.g. development dependencies). 82 | # You can install these using the following syntax, for example: 83 | # $ pip install -e .[dev,test] 84 | extras_require={"dev": ["check-manifest", "pytest"], "test": ["pytest", "pytest-cov"],}, 85 | # If there are data files included in your packages that need to be 86 | # installed, specify them here. If using Python 2.6 or less, then these 87 | # have to be included in MANIFEST.in as well. 88 | # package_data={ 89 | # 'sample': ['logging.conf'], 90 | # }, 91 | # Although 'package_data' is the preferred approach, in some case you may 92 | # need to place data files outside of your packages. 93 | # see http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files 94 | # In this case, 'data_file' will be installed into '/my_data' 95 | # data_files=[('my_data', ['data/data_file'])], 96 | # To provide executable scripts, use entry points in preference to the 97 | # "scripts" keyword. Entry points provide cross-platform support and allow 98 | # pip to create the appropriate form of executable for the target platform. 99 | entry_points={"console_scripts": ["sample=sample:main",],}, 100 | ) 101 | -------------------------------------------------------------------------------- /tests/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Always prefer setuptools over distutils 5 | from setuptools import setup, find_packages 6 | from codecs import open # To use a consistent encoding 7 | from os import path 8 | import io 9 | 10 | NAME = "trading_ig" 11 | filename = "%s/version.py" % NAME 12 | with open(filename) as f: 13 | exec(f.read()) 14 | 15 | here = path.abspath(path.dirname(__file__)) 16 | 17 | 18 | def readme(): 19 | filename = path.join(here, "README.rst") 20 | with io.open(filename, "rt", encoding="UTF-8") as f: 21 | return f.read() 22 | 23 | 24 | setup( 25 | name=NAME, 26 | # Versions should comply with PEP440. For a discussion on single-sourcing 27 | # the version across setup.py and the project code, see 28 | # https://packaging.python.org/en/latest/development.html#single-sourcing-the-version 29 | # version='0.0.1', 30 | version=__version__, 31 | description="A lightweight wrapper for the IG Markets API written in Python", 32 | long_description=readme(), 33 | # The project's main homepage. 34 | url=__url__, 35 | # Author details 36 | author=__author__, 37 | author_email=__author_email__, 38 | # Choose your license 39 | license=__license__, 40 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 41 | classifiers=[ 42 | # How mature is this project? Common values are 43 | # 3 - Alpha 44 | # 4 - Beta 45 | # 5 - Production/Stable 46 | "Development Status :: 3 - Alpha", 47 | # Indicate who your project is intended for 48 | "Environment :: Console", 49 | # 'Topic :: Software Development :: Build Tools', 50 | "Intended Audience :: Science/Research", 51 | "Operating System :: OS Independent", 52 | # Specify the Python versions you support here. In particular, ensure 53 | # that you indicate whether you support Python 2, Python 3 or both. 54 | "Programming Language :: Cython", 55 | "Programming Language :: Python", 56 | "Programming Language :: Python :: 3.6", 57 | "Programming Language :: Python :: 3.7", 58 | "Programming Language :: Python :: 3.8", 59 | "Topic :: Scientific/Engineering", 60 | # Pick your license as you wish (should match "license" above) 61 | "License :: OSI Approved :: BSD License", 62 | ], 63 | python_requires='>=3.6', 64 | # What does your project relate to? 65 | keywords="trading, spread betting, CFDs", 66 | # You can just specify the packages manually here if your project is 67 | # simple. Or you can use find_packages(). 68 | packages=find_packages(exclude=["contrib", "docs", "tests*"]), 69 | # List run-time dependencies here. These will be installed by pip when your 70 | # project is installed. For an analysis of "install_requires" vs pip's 71 | # requirements files see: 72 | # https://packaging.python.org/en/latest/technical.html#install-requires-vs-requirements-files 73 | install_requires=[ 74 | "munch==2.5.0", 75 | "pycryptodome==3.9.8", 76 | "requests==2.24.0", 77 | "requests-cache==0.5.2", 78 | "six==1.15.0", 79 | "pandas==1.0.5", 80 | ], # bunch->lunch->infi.bunch->munch 81 | # List additional groups of dependencies here (e.g. development dependencies). 82 | # You can install these using the following syntax, for example: 83 | # $ pip install -e .[dev,test] 84 | extras_require={"dev": ["check-manifest", "pytest"], "test": ["pytest", "pytest-cov"],}, 85 | # If there are data files included in your packages that need to be 86 | # installed, specify them here. If using Python 2.6 or less, then these 87 | # have to be included in MANIFEST.in as well. 88 | # package_data={ 89 | # 'sample': ['logging.conf'], 90 | # }, 91 | # Although 'package_data' is the preferred approach, in some case you may 92 | # need to place data files outside of your packages. 93 | # see http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files 94 | # In this case, 'data_file' will be installed into '/my_data' 95 | # data_files=[('my_data', ['data/data_file'])], 96 | # To provide executable scripts, use entry points in preference to the 97 | # "scripts" keyword. Entry points provide cross-platform support and allow 98 | # pip to create the appropriate form of executable for the target platform. 99 | entry_points={"console_scripts": ["sample=sample:main",],}, 100 | ) 101 | -------------------------------------------------------------------------------- /predefined_functions/temp_algo_tut.py: -------------------------------------------------------------------------------- 1 | from predefined_functions.defined_functionality import Defined_Functionality 2 | from datetime import datetime 3 | import pandas as pd 4 | 5 | class Algo0: 6 | def __init__(self): 7 | self.df = Defined_Functionality() 8 | 9 | self.list_of_epics = ['IX.D.DOW.DAILY.IP'] 10 | self.df.set_epics_to_look_for(epic_list=self.list_of_epics) 11 | 12 | self.map_epic_data_minute={} 13 | for epic in self.list_of_epics: 14 | self.map_epic_data_minute[epic] = [] 15 | 16 | self.first_timestamp = None 17 | 18 | 19 | 20 | def run(self): 21 | 22 | while(True): 23 | try: 24 | epic = self.list_of_epics[0] 25 | signals = self.signal_generation(epic) 26 | self.create_positions(epic=epic, signals_levels=signals) 27 | self.closing_positions(epic=epic, signals= signals) 28 | 29 | except Exception as e: 30 | print(e, " error in the looping for the defined_functionality") 31 | 32 | def closing_positions(self, epic, signals): 33 | position = self.df.find_open_position_by_epic(epic=epic) 34 | 35 | if len(position) == 0: 36 | return 37 | 38 | if isinstance(position[0],pd.core.series.Series): 39 | if signals == None: 40 | return 41 | 42 | if (signals["BUY"] != None and (position[0]["position"]["direction"] != "BUY")): 43 | self.df.close_position(position=position[0]) 44 | 45 | elif (signals["SELL"] != None and (position[0]["position"]["direction"] != "SELL")): 46 | self.df.close_position(position=position[0]) 47 | 48 | def create_positions(self, epic, signals_levels): 49 | if signals_levels == None: 50 | return 51 | key = None 52 | if signals_levels["BUY"] != None: 53 | key = "BUY" 54 | elif signals_levels["SELL"] != None: 55 | key = "SELL" 56 | 57 | 58 | position = self.df.find_open_position_by_epic(epic=epic) 59 | 60 | if len(position) != 0: 61 | return position 62 | 63 | 64 | create_position = self.df.create_open_position(epic=epic, direction=key, size=0.5) 65 | 66 | return create_position 67 | 68 | 69 | def signal_generation(self, epic): 70 | signals_levels = None 71 | # minute_10 = 60 * 10 72 | # minute_10 = 60 73 | minute_10 = 1 74 | datetime_now = datetime.now() 75 | data = None 76 | 77 | if (self.first_timestamp != None): 78 | difference = (datetime_now - self.first_timestamp) 79 | 80 | if (difference.seconds > minute_10): 81 | data = self.df.get_market_data(epic=epic) 82 | self.first_timestamp = datetime_now 83 | self.map_epic_data_minute[epic].append(data) 84 | 85 | else: 86 | data = self.df.get_market_data(epic=epic) 87 | self.first_timestamp = datetime_now 88 | 89 | self.map_epic_data_minute[epic].append(data) 90 | # self.finding_lows_highs(data=data) 91 | 92 | if len(self.map_epic_data_minute[epic]) > 3: 93 | self.map_epic_data_minute[epic].pop(0) 94 | 95 | sell_level = None 96 | buy_level = None 97 | 98 | object_epic_data = self.map_epic_data_minute[epic][-1] 99 | bid = object_epic_data["snapshot"]["bid"] 100 | offer = object_epic_data["snapshot"]["offer"] 101 | high = object_epic_data["snapshot"]["high"] 102 | low = object_epic_data["snapshot"]["low"] 103 | 104 | object_epic_data = self.map_epic_data_minute[epic][-2] 105 | bid_old = object_epic_data["snapshot"]["bid"] 106 | offer_old = object_epic_data["snapshot"]["offer"] 107 | high_old = object_epic_data["snapshot"]["high"] 108 | low_old = object_epic_data["snapshot"]["low"] 109 | 110 | offer_diff = offer - offer_old 111 | bid_diff = bid - bid_old 112 | 113 | # if offer_diff > 0.1: 114 | buy_level = 1 115 | # elif bid_diff < -0.1: 116 | sell_level = 1 117 | 118 | 119 | self.map_epic_data_minute[epic] = [] 120 | # instead here we are using bid/offer 121 | 122 | if (sell_level == None) and (buy_level == None): 123 | return None 124 | 125 | signals_levels = { 126 | "SELL": sell_level, 127 | "BUY": buy_level 128 | } 129 | 130 | return signals_levels 131 | 132 | 133 | -------------------------------------------------------------------------------- /sending_orders/rest_ig_sending_orders.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | IG Markets REST API sample with Python 6 | 2015 FemtoTrader 7 | """ 8 | 9 | from trading_ig import IGService 10 | from trading_ig.config import config 11 | import logging 12 | 13 | logger = logging.getLogger(__name__) 14 | logger.setLevel(logging.DEBUG) 15 | 16 | # if you need to cache to DB your requests 17 | from datetime import timedelta 18 | import requests_cache 19 | 20 | 21 | def main(): 22 | logging.basicConfig(level=logging.DEBUG) 23 | 24 | expire_after = timedelta(hours=1) 25 | session = requests_cache.CachedSession( 26 | cache_name='cache', backend='sqlite', expire_after=expire_after 27 | ) 28 | # set expire_after=None if you don't want cache expiration 29 | # set expire_after=0 if you don't want to cache queries 30 | 31 | #config = IGServiceConfig() 32 | 33 | # no cache 34 | ig_service = IGService( 35 | config.username, config.password, config.api_key, config.acc_type 36 | ) 37 | 38 | # if you want to globally cache queries 39 | #ig_service = IGService(config.username, config.password, config.api_key, config.acc_type, session) 40 | 41 | ig_service.create_session() 42 | 43 | accounts = ig_service.fetch_accounts() 44 | print("accounts:\n%s" % accounts) 45 | """ 46 | # - as it is set to default ift no longer needed gets the account to the spread betting one , the one specified in the config file 47 | ig_service.switch_account(account_id=config.acc_number, default_account=True) 48 | """ 49 | 50 | #open_positions = ig_service.fetch_open_positions() 51 | #print("open_positions:\n%s" % open_positions) 52 | 53 | print("") 54 | 55 | working_orders = ig_service.fetch_working_orders() 56 | print("working_orders:\n%s" % working_orders) 57 | 58 | print("") 59 | 60 | currency_code = "GBP" 61 | direction = "BUY" 62 | epic = "IX.D.FTSE.DAILY.IP" 63 | expiry = "DFB" 64 | guaranteed_stop = False 65 | # entering price 66 | level = 6801.3 67 | # Pound per point size 68 | size = 1 69 | time_in_force = "GOOD_TILL_CANCELLED" 70 | # limit orders are now called STOP 71 | order_type = "STOP" 72 | limit_distance = None 73 | stop_distance = 160 74 | 75 | # """Creates an OTC working order""" 76 | response = ig_service.create_working_order( 77 | currency_code=currency_code, 78 | direction=direction, 79 | epic=epic, 80 | expiry=expiry, 81 | guaranteed_stop=guaranteed_stop, 82 | level=level, 83 | size=size, 84 | time_in_force=time_in_force, 85 | order_type=order_type, 86 | limit_distance=limit_distance, 87 | stop_distance=stop_distance 88 | ) 89 | 90 | # ig_service.create_working_order( 91 | # currency_code="GBP", 92 | # direction="BUY", 93 | # epic="CS.D.BITCOIN.TODAY.IP", 94 | # expiry="DFB", 95 | # force_open=True, 96 | # guaranteed_stop=True, 97 | # stop_distance=1100.0, 98 | # size=0.50, 99 | # time_in_force="GOOD_TILL_CANCELLED", 100 | # order_type="LIMIT", 101 | # limit_distance=1000.0, 102 | # level=1000.0) 103 | 104 | 105 | print("") 106 | 107 | working_orders = ig_service.fetch_working_orders() 108 | print("working_orders:\n%s" % working_orders) 109 | 110 | 111 | # response is a dict -> response["price"] -> DataFrame (Multi-level df)-> so df = response["price"] 112 | # df -> df["ask"] -> Open,High,Low,Close 113 | # df -> df["bid"] -> Open,High,Low,Close 114 | # df -> df["last"] -> but these are usually None values = (Open,High,Low,Close) 115 | print(response) 116 | # Exception: error.public-api.exceeded-account-historical-data-allowance 117 | 118 | # if you want to cache this query 119 | #response = ig_service.fetch_historical_prices_by_epic_and_num_points(epic, resolution, num_points, session) 120 | 121 | #df_ask = response['prices']['ask'] 122 | #print("ask prices:\n%s" % df_ask) 123 | 124 | #(start_date, end_date) = ('2015-09-15', '2015-09-28') 125 | #response = ig_service.fetch_historical_prices_by_epic_and_date_range(epic, resolution, start_date, end_date) 126 | 127 | # if you want to cache this query 128 | #response = ig_service.fetch_historical_prices_by_epic_and_date_range(epic, resolution, start_date, end_date, session) 129 | #df_ask = response['prices']['ask'] 130 | #print("ask prices:\n%s" % df_ask) 131 | 132 | 133 | 134 | # check this out and see what you can do to get all the market data information 135 | 136 | 137 | 138 | if __name__ == '__main__': 139 | main() 140 | -------------------------------------------------------------------------------- /Linked_to_biggest_previous_day_difference_in_price/adding_all_realtime_IG_data_to_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | IG Markets REST API sample with Python 6 | 2015 FemtoTrader 7 | """ 8 | 9 | from trading_ig import IGService 10 | from trading_ig.config import config 11 | import logging 12 | # format to 13 | # # from folder.file import class 14 | # from getting_instrument_based_data.navigate_tree import NavigateTree 15 | 16 | logger = logging.getLogger(__name__) 17 | logger.setLevel(logging.DEBUG) 18 | 19 | # if you need to cache to DB your requests 20 | from datetime import timedelta 21 | import requests_cache 22 | import time 23 | import os 24 | import json 25 | import pandas as pd 26 | 27 | 28 | counter = -1 29 | ig_service = None 30 | 31 | 32 | 33 | def login(): 34 | expire_after = timedelta(hours=1) 35 | session = requests_cache.CachedSession( 36 | cache_name='cache', backend='sqlite', expire_after=expire_after 37 | ) 38 | api_key = increment_api_key() 39 | 40 | global ig_service 41 | 42 | # no cache 43 | ig_service = IGService( 44 | config.username, config.password, api_key, config.acc_type 45 | ) 46 | ig_service.create_session() 47 | 48 | 49 | 50 | def main(): 51 | 52 | login() 53 | 54 | date = "2020-12-10_2021-02-10" 55 | # date = "2020-09-10_2020-12-10" 56 | time_interval = "5Min" 57 | get_data(date, time_interval) 58 | 59 | 60 | 61 | def get_data(date, time_interval): 62 | 63 | histroical_path_location = "D:\Data\IG_Instrument\historical_data\\" + time_interval + "\\" + date 64 | 65 | 66 | holding_list = [] 67 | 68 | files = os.listdir(histroical_path_location) 69 | 70 | for f in files: 71 | # save the data 72 | try: 73 | name = f 74 | epic = name.split("_ID_")[1] 75 | data = get_details_about_epic(epic) 76 | # get the magin requirement from here --------------------------------------------------------------------------------------------- 77 | data = json.loads(json.dumps(data)) 78 | # 79 | # map_of_items = { 80 | # "value" : data["instrument"]["marginFactor"], 81 | # "unit" : data["instrument"]["marginFactorUnit"]} 82 | # 83 | # difference_required = map_of_items["value"] 84 | # # otherwise the unit is POINTS 85 | # if map_of_items["unit"] == "PERCENTAGE": 86 | # difference_required = difference_required / 100 87 | # 88 | # difference_required * current_price 89 | temp = data["instrument"].copy() 90 | temp.update(data["dealingRules"]) 91 | temp.update(data["snapshot"]) 92 | temp["file_name"] = name 93 | 94 | 95 | whole_file_location = os.path.join(histroical_path_location, name) 96 | historical_data = pd.read_csv(whole_file_location, header=[0, 1], index_col=0) 97 | historical_data.index = pd.to_datetime(historical_data.index) 98 | 99 | bid = historical_data.iloc[0]["bid"]["Close"] 100 | ask = historical_data.iloc[0]["ask"]["Close"] 101 | spread = ask - bid 102 | 103 | temp["spread"] = spread 104 | temp["average"] = (bid + ask) / 2.0 105 | temp["diff_high-low"] = historical_data["bid"]["High"].max() - historical_data["bid"]["Low"].min() 106 | # could divide by zero and cause an error but would be caught by try and except clause 107 | temp["percent_spread-hl"] = (temp["spread"] / temp["diff_high-low"] * 100) 108 | 109 | 110 | holding_list.append(temp) 111 | 112 | 113 | 114 | except Exception as e: 115 | print(e) 116 | dataframe = pd.DataFrame(holding_list) 117 | 118 | dataframe.to_csv("D:\Stock_Analysis\IG_Data_Fixing\Results\All_instrument_data_added.csv") 119 | 120 | def get_details_about_epic(epic): 121 | global ig_service 122 | while(True): 123 | try: 124 | map_of_data = ig_service.fetch_market_by_epic(epic) 125 | return map_of_data 126 | except Exception as e: 127 | print(e) 128 | login() 129 | 130 | 131 | def increment_api_key(): 132 | key = "" 133 | global counter 134 | flag = True 135 | while (flag): 136 | try: 137 | counter += 1 138 | # has 12000 api keys 139 | fp = open("D:\Stock_Analysis\ig-markets-api-python-library-master\generate_api_keys\IG_api_keys_raw.txt") 140 | for i, line in enumerate(fp): 141 | if i == counter: 142 | key = line.split("\n")[0] 143 | flag = False 144 | break 145 | 146 | fp.close() 147 | except: 148 | counter = -1 149 | 150 | return key 151 | 152 | 153 | 154 | if __name__ == '__main__': 155 | main() 156 | -------------------------------------------------------------------------------- /getting_instrument_based_data/rest_ig_get_instrument_data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | import pandas as pd 5 | 6 | from trading_ig import IGService 7 | from trading_ig.config import config 8 | 9 | from datetime import timedelta 10 | import requests_cache 11 | import time 12 | import os 13 | import json 14 | 15 | 16 | counter = -1 17 | ig_service = None 18 | list_of_instruments = [] 19 | 20 | 21 | def login(): 22 | expire_after = timedelta(hours=1) 23 | session = requests_cache.CachedSession( 24 | cache_name='cache', backend='sqlite', expire_after=expire_after 25 | ) 26 | api_key = increment_api_key() 27 | 28 | global ig_service 29 | 30 | # no cache 31 | ig_service = IGService( 32 | config.username, config.password, api_key, config.acc_type 33 | ) 34 | ig_service.create_session() 35 | 36 | 37 | def main(): 38 | 39 | login() 40 | map_dataframe = ig_service.fetch_top_level_navigation_nodes() 41 | # list_of_stringNodes = (map_dataframe["nodes"])["id"].tolist() 42 | template_recurse(map_dataframe, ig_service) 43 | 44 | 45 | 46 | def template_recurse(map_dataframe, ig_service): 47 | node_list = map_dataframe["nodes"]["id"].tolist() 48 | # node_list = ["97601","195235"] 49 | name_list = map_dataframe["nodes"]["name"].tolist() 50 | # name_list = ["Indices","Forex"] 51 | set_nodes = set() 52 | 53 | recurse_overNodes(name_list, node_list, set_nodes, ig_service, []) 54 | 55 | def recurse_overNodes(name_list, node_list, set_nodes, ig_service, current_name): 56 | while len(node_list) != 0 : 57 | # needs to be -1 as the last item gets popped 58 | node = node_list[-1] 59 | 60 | if node in set_nodes: 61 | node_list.pop() 62 | name_list.pop() 63 | continue 64 | 65 | current_name.append(name_list[-1]) 66 | 67 | set_nodes.add(node) 68 | map_dataframe = get_node_to_node_data(ig_service, node) 69 | 70 | if (map_dataframe["nodes"].size == 0): 71 | 72 | # save the data 73 | try: 74 | epic_id = map_dataframe["markets"]["epic"][0] 75 | if epic_id == "": 76 | raise Exception("No id") 77 | # save data 78 | map_data = get_details_about_epic(ig_service, epic_id) 79 | map_data["instrument"]["location"] = "_".join(current_name) 80 | # data_string = json.dumps(map_data) 81 | 82 | temp = map_data["instrument"].copy() 83 | temp.update(map_data["dealingRules"]) 84 | temp.update(map_data["snapshot"]) 85 | 86 | global list_of_instruments 87 | list_of_instruments.append(temp) 88 | save_to_file(list_of_instruments) 89 | 90 | except Exception as e: 91 | print(e) 92 | 93 | current_name.pop() 94 | 95 | else: 96 | temp_names = map_dataframe["nodes"]["name"].tolist() 97 | temp_id = map_dataframe["nodes"]["id"].tolist() 98 | recurse_overNodes(temp_names, temp_id, set_nodes, ig_service , current_name) 99 | current_name.pop() 100 | 101 | 102 | 103 | 104 | def get_node_to_node_data(ig_service,node): 105 | while(True): 106 | try: 107 | 108 | map_dataframe = ig_service.fetch_sub_nodes_by_node(node=node) 109 | return map_dataframe 110 | except Exception as e: 111 | print(e) 112 | login() 113 | 114 | def get_details_about_epic(ig_service, epic): 115 | while(True): 116 | try: 117 | map_of_data = ig_service.fetch_market_by_epic(epic) 118 | return map_of_data 119 | except Exception as e: 120 | print(e) 121 | login() 122 | # time.sleep(2) 123 | 124 | def save_to_file(data): 125 | 126 | try: 127 | directory = r"D:/Stock_Analysis/ig-markets-api-python-library-master/Data/SpreadBetting/" 128 | 129 | if not os.path.exists(directory): 130 | os.mkdir(directory) 131 | 132 | file = "instruments_new.csv" 133 | filename= directory+file 134 | df = pd.DataFrame(data) 135 | df.to_csv(filename) 136 | 137 | except Exception as e: 138 | print("failed to write to file " + str(e)) 139 | 140 | 141 | def increment_api_key(): 142 | key = "" 143 | global counter 144 | flag = True 145 | while (flag): 146 | try: 147 | counter += 1 148 | fp = open("D:\Stock_Analysis\ig-markets-api-python-library-master\generate_api_keys\IG_api_keys_raw.txt") 149 | for i, line in enumerate(fp): 150 | if i == counter: 151 | key = line.split("\n")[0] 152 | flag = False 153 | break 154 | 155 | fp.close() 156 | except: 157 | counter = -1 158 | 159 | return key 160 | 161 | 162 | 163 | if __name__ == '__main__': 164 | main() 165 | -------------------------------------------------------------------------------- /predefined_functions/algo_doing_simple_tasks.py: -------------------------------------------------------------------------------- 1 | from trading_ig.config import config 2 | import logging 3 | 4 | logger = logging.getLogger(__name__) 5 | logger.setLevel(logging.DEBUG) 6 | 7 | # if you need to cache to DB your requests 8 | from datetime import timedelta 9 | import requests_cache 10 | from getting_realtime_data.data_retrieval import Data_Retrieval 11 | from sending_orders.order_management import Order_Management 12 | from management_of_position.position_management import Position_Management 13 | from predefined_functions.initialisation import Initialisation 14 | from get_data.get_market_data import Get_Market_Data 15 | import time 16 | from datetime import datetime, timedelta 17 | from predefined_functions.defined_functionality import Defined_Functionality 18 | import pandas 19 | import traceback 20 | 21 | # the newest one where you make market order base on price movements 5 or more and try to catch the trend 22 | 23 | class Algo0: 24 | def __init__(self): 25 | logging.basicConfig(level=logging.INFO) 26 | self.df = Defined_Functionality() 27 | 28 | self.list_of_epics = ['IX.D.DOW.DAILY.IP'] 29 | # list_of_epics = ['CS.D.EURUSD.TODAY.IP'] 30 | 31 | self.df.set_epics_to_look_for(epic_list=self.list_of_epics) 32 | 33 | self.map_epic_data_minute={} 34 | for epic in self.list_of_epics: 35 | self.map_epic_data_minute[epic] = [] 36 | 37 | 38 | self.first_timestamp = None 39 | self.high = None 40 | self.low = None 41 | 42 | def setup(self): 43 | self.df.get_market_data() 44 | # self.df.update_stop_level_bands() 45 | 46 | 47 | def run(self): 48 | 49 | 50 | self.df.start_data_from_market_data_socket(self.list_of_epics) 51 | 52 | while(True): 53 | try: 54 | # self.setup() 55 | epic=self.list_of_epics[0] 56 | data = self.df.get_quote_data_from_socket(epic) 57 | print(data) 58 | 59 | 60 | # for epic in self.map_epic_data_minute.keys(): 61 | # signals_and_levels = self.signal_generation(epic=epic) 62 | # self.create_orders(epic=epic, signals_levels=signals_and_levels) 63 | 64 | except Exception as e: 65 | print(e, " error in the looping for the defined_functionality") 66 | traceback.print_exc() 67 | 68 | 69 | def create_orders(self, epic, signals_levels): 70 | if signals_levels == None: 71 | return 72 | key = None 73 | if signals_levels["BUY"] != None: 74 | key = "BUY" 75 | elif signals_levels["SELL"] != None: 76 | key = "SELL" 77 | 78 | 79 | position = self.df.find_open_position_by_epic(epic=epic) 80 | 81 | if isinstance(position,pandas.core.series.Series): 82 | print("position already exists", position) 83 | return position 84 | 85 | create_position = self.df.create_open_position(epic=epic, direction=key, size=0.5) 86 | 87 | return create_position 88 | 89 | 90 | def signal_generation(self, epic): 91 | signals_levels = None 92 | # minute_10 = 60 * 10 93 | # minute_10 = 60 94 | minute_10 = 6 95 | datetime_now = datetime.now() 96 | data = None 97 | if (self.first_timestamp != None): 98 | difference = (datetime_now - self.first_timestamp) 99 | data = self.df.get_market_data(epic=epic) 100 | # self.finding_lows_highs(data=data) 101 | 102 | if (difference.seconds > minute_10): 103 | data = self.df.get_market_data(epic=epic) 104 | self.first_timestamp = datetime_now 105 | self.map_epic_data_minute[epic].append(data) 106 | # self.finding_lows_highs(data=data, reset=True) 107 | 108 | else: 109 | data = self.df.get_market_data(epic=epic) 110 | self.first_timestamp = datetime_now 111 | 112 | self.map_epic_data_minute[epic].append(data) 113 | # self.finding_lows_highs(data=data) 114 | 115 | if len(self.map_epic_data_minute[epic]) > 3: 116 | self.map_epic_data_minute[epic].pop(0) 117 | 118 | 119 | sell_level = None 120 | buy_level = None 121 | 122 | object_epic_data = self.map_epic_data_minute[epic][-1] 123 | bid = object_epic_data["snapshot"]["bid"] 124 | offer = object_epic_data["snapshot"]["offer"] 125 | high = object_epic_data["snapshot"]["high"] 126 | low = object_epic_data["snapshot"]["low"] 127 | 128 | object_epic_data = self.map_epic_data_minute[epic][-2] 129 | bid_old = object_epic_data["snapshot"]["bid"] 130 | offer_old = object_epic_data["snapshot"]["offer"] 131 | high_old = object_epic_data["snapshot"]["high"] 132 | low_old = object_epic_data["snapshot"]["low"] 133 | 134 | offer_diff = offer - offer_old 135 | bid_diff = bid - bid_old 136 | 137 | if offer_diff > 10: 138 | buy_level = 1 139 | elif bid_diff < -10: 140 | sell_level = 1 141 | 142 | self.map_epic_data_minute[epic] = [] 143 | # instead here we are using bid/offer 144 | 145 | if (sell_level == None) and (buy_level == None): 146 | return None 147 | 148 | signals_levels = { 149 | "SELL": sell_level, 150 | "BUY": buy_level 151 | } 152 | 153 | return signals_levels 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /predefined_functions/algo_minute_on_quotes.py: -------------------------------------------------------------------------------- 1 | from trading_ig.config import config 2 | import logging 3 | 4 | logger = logging.getLogger(__name__) 5 | logger.setLevel(logging.DEBUG) 6 | 7 | # if you need to cache to DB your requests 8 | from datetime import timedelta 9 | import requests_cache 10 | from getting_realtime_data.data_retrieval import Data_Retrieval 11 | from sending_orders.order_management import Order_Management 12 | from management_of_position.position_management import Position_Management 13 | from predefined_functions.initialisation import Initialisation 14 | from get_data.get_market_data import Get_Market_Data 15 | import time 16 | from datetime import datetime, timedelta 17 | from predefined_functions.defined_functionality import Defined_Functionality 18 | import pandas 19 | import traceback 20 | 21 | # the newest one where you make market order base on price movements 5 or more and try to catch the trend 22 | 23 | class Algo0: 24 | def __init__(self): 25 | logging.basicConfig(level=logging.INFO) 26 | self.df = Defined_Functionality() 27 | 28 | list_of_epics = ['IX.D.DOW.DAILY.IP'] 29 | # list_of_epics = ['CS.D.EURUSD.TODAY.IP'] 30 | 31 | self.df.set_epics_to_look_for(epic_list=list_of_epics) 32 | 33 | self.map_epic_data_minute={} 34 | for epic in list_of_epics: 35 | self.map_epic_data_minute[epic] = [] 36 | 37 | 38 | self.first_timestamp = None 39 | self.high = None 40 | self.low = None 41 | 42 | def setup(self): 43 | self.df.initialise_connection() 44 | time.sleep(2) 45 | self.df.get_market_data() 46 | self.df.update_stop_level_bands() 47 | 48 | 49 | def run(self): 50 | 51 | while(True): 52 | try: 53 | self.setup() 54 | 55 | for epic in self.map_epic_data_minute.keys(): 56 | signals_and_levels = self.signal_generation(epic=epic) 57 | self.create_orders(epic=epic, signals_levels=signals_and_levels) 58 | 59 | except Exception as e: 60 | print(e, " error in the looping for the defined_functionality") 61 | traceback.print_exc() 62 | 63 | 64 | def create_orders(self, epic, signals_levels): 65 | if signals_levels == None: 66 | return 67 | key = None 68 | if signals_levels["BUY"] != None: 69 | key = "BUY" 70 | elif signals_levels["SELL"] != None: 71 | key = "SELL" 72 | 73 | 74 | position = self.df.find_open_position_by_epic(epic=epic) 75 | 76 | if isinstance(position,pandas.core.series.Series): 77 | print("position already exists", position) 78 | return position 79 | 80 | create_position = self.df.create_open_position(epic=epic, direction=key, size=0.5) 81 | 82 | return create_position 83 | 84 | 85 | def signal_generation(self, epic): 86 | signals_levels = None 87 | # minute_10 = 60 * 10 88 | # minute_10 = 60 89 | minute_10 = 6 90 | datetime_now = datetime.now() 91 | data = None 92 | if (self.first_timestamp != None): 93 | difference = (datetime_now - self.first_timestamp) 94 | data = self.df.get_market_data(epic=epic) 95 | # self.finding_lows_highs(data=data) 96 | 97 | if (difference.seconds > minute_10): 98 | data = self.df.get_market_data(epic=epic) 99 | self.first_timestamp = datetime_now 100 | self.map_epic_data_minute[epic].append(data) 101 | # self.finding_lows_highs(data=data, reset=True) 102 | 103 | else: 104 | data = self.df.get_market_data(epic=epic) 105 | self.first_timestamp = datetime_now 106 | 107 | self.map_epic_data_minute[epic].append(data) 108 | # self.finding_lows_highs(data=data) 109 | 110 | if len(self.map_epic_data_minute[epic]) > 3: 111 | self.map_epic_data_minute[epic].pop(0) 112 | 113 | 114 | sell_level = None 115 | buy_level = None 116 | 117 | object_epic_data = self.map_epic_data_minute[epic][-1] 118 | bid = object_epic_data["snapshot"]["bid"] 119 | offer = object_epic_data["snapshot"]["offer"] 120 | high = object_epic_data["snapshot"]["high"] 121 | low = object_epic_data["snapshot"]["low"] 122 | 123 | object_epic_data = self.map_epic_data_minute[epic][-2] 124 | bid_old = object_epic_data["snapshot"]["bid"] 125 | offer_old = object_epic_data["snapshot"]["offer"] 126 | high_old = object_epic_data["snapshot"]["high"] 127 | low_old = object_epic_data["snapshot"]["low"] 128 | 129 | offer_diff = offer - offer_old 130 | bid_diff = bid - bid_old 131 | # as we are following the trends 132 | # # if offer_diff > 5: 133 | # if offer_diff > 0: 134 | # buy_level = 1 135 | # # elif offer_diff < -5: 136 | # elif offer_diff < 0: 137 | # sell_level = 1 138 | 139 | if offer_diff > 10: 140 | buy_level = 1 141 | elif bid_diff < -10: 142 | sell_level = 1 143 | 144 | self.map_epic_data_minute[epic] = [] 145 | # instead here we are using bid/offer 146 | 147 | if (sell_level == None) and (buy_level == None): 148 | return None 149 | 150 | signals_levels = { 151 | "SELL": sell_level, 152 | "BUY": buy_level 153 | } 154 | 155 | return signals_levels 156 | 157 | def finding_lows_highs(self, data, reset = False): 158 | 159 | bid = data["snapshot"]["bid"] 160 | offer = data["snapshot"]["offer"] 161 | 162 | if reset: 163 | epic = data["instrument"]["epic"] 164 | object_dict = self.map_epic_data_minute[epic][-1] 165 | object_dict["snapshot"]["high"] = self.high 166 | object_dict["snapshot"]["low"] = self.low 167 | self.map_epic_data_minute[epic][-1] = object_dict 168 | # start looking at the new interval 169 | if self.high == None or reset: 170 | self.high = offer 171 | if self.low == None or reset: 172 | self.low = bid 173 | 174 | if bid < self.low: 175 | self.low = bid 176 | if offer > self.high: 177 | self.high = offer 178 | 179 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /predefined_functions/algo_close_positons_in_profit.py: -------------------------------------------------------------------------------- 1 | from trading_ig.config import config 2 | import logging 3 | 4 | logger = logging.getLogger(__name__) 5 | logger.setLevel(logging.DEBUG) 6 | 7 | # if you need to cache to DB your requests 8 | from datetime import timedelta 9 | import requests_cache 10 | from getting_realtime_data.data_retrieval import Data_Retrieval 11 | from sending_orders.order_management import Order_Management 12 | from management_of_position.position_management import Position_Management 13 | from predefined_functions.initialisation import Initialisation 14 | from get_data.get_market_data import Get_Market_Data 15 | import time 16 | from datetime import datetime, timedelta 17 | from predefined_functions.defined_functionality import Defined_Functionality 18 | import pandas 19 | import traceback 20 | 21 | 22 | class Algo0: 23 | def __init__(self): 24 | self.df = Defined_Functionality() 25 | 26 | 27 | def setup(self): 28 | # self.df.get_market_data() 29 | self.df.update_stop_level_bands() 30 | 31 | 32 | def run(self): 33 | 34 | while(True): 35 | try: 36 | self.setup() 37 | 38 | except Exception as e: 39 | print(e, " error in the looping for the defined_functionality") 40 | traceback.print_exc() 41 | 42 | 43 | 44 | def create_orders(self, epic, signals_levels): 45 | if signals_levels == None: 46 | return 47 | key = None 48 | if signals_levels["BUY"] != None: 49 | key = "BUY" 50 | elif signals_levels["SELL"] != None: 51 | key = "SELL" 52 | 53 | self.df.cancel_orders_by_epic(epic=epic) 54 | position = self.df.find_open_position_by_epic(epic=epic) 55 | if isinstance(position,pandas.core.series.Series): 56 | print("position already exists", position) 57 | return position 58 | 59 | order = self.df.create_working_order_at_point(epic=epic, direction=key,price_order_level=signals_levels[key]) 60 | return order 61 | 62 | 63 | # def signal_generation(self, epic): 64 | # signals_levels = None 65 | # # minute_10 = 60 * 10 66 | # minute_10 = 60 * 10 67 | # datetime_now = datetime.now() 68 | # data = None 69 | # if (self.first_timestamp != None): 70 | # difference = (datetime_now - self.first_timestamp) 71 | # data = self.df.get_market_data(epic=epic) 72 | # self.finding_lows_highs(data=data) 73 | # 74 | # if (difference.seconds > minute_10): 75 | # data = self.df.get_market_data(epic=epic) 76 | # self.first_timestamp = datetime_now 77 | # self.map_epic_data_10_minute[epic].append(data) 78 | # self.finding_lows_highs(data=data, reset=True) 79 | # 80 | # else: 81 | # data = self.df.get_market_data(epic=epic) 82 | # self.first_timestamp = datetime_now 83 | # 84 | # self.map_epic_data_10_minute[epic].append(data) 85 | # self.finding_lows_highs(data=data) 86 | # 87 | # if len(self.map_epic_data_10_minute[epic]) > 4: 88 | # self.map_epic_data_10_minute[epic].pop(0) 89 | # 90 | # 91 | # sell_level = None 92 | # buy_level = None 93 | # 94 | # difference_bid = [] 95 | # difference_offer = [] 96 | # difference_low = [] 97 | # difference_high = [] 98 | # 99 | # object_epic_data = self.map_epic_data_10_minute[epic][0] 100 | # bid = object_epic_data["snapshot"]["bid"] 101 | # offer = object_epic_data["snapshot"]["offer"] 102 | # high = object_epic_data["snapshot"]["high"] 103 | # low = object_epic_data["snapshot"]["low"] 104 | # 105 | # for i in range(1, len(self.map_epic_data_10_minute[epic])): 106 | # 107 | # object_epic_data = self.map_epic_data_10_minute[epic][i] 108 | # bid = object_epic_data["snapshot"]["bid"] - bid 109 | # offer = object_epic_data["snapshot"]["offer"] - offer 110 | # high = object_epic_data["snapshot"]["high"] - high 111 | # low = object_epic_data["snapshot"]["low"] - low 112 | # 113 | # difference_bid.append(bid) 114 | # difference_offer.append(offer) 115 | # difference_low.append(low) 116 | # difference_high.append(high) 117 | # # the high/low becomes the levels we enter orders at 118 | # bid = object_epic_data["snapshot"]["bid"] 119 | # offer = object_epic_data["snapshot"]["offer"] 120 | # high = object_epic_data["snapshot"]["high"] 121 | # low = object_epic_data["snapshot"]["low"] 122 | # 123 | # self.map_epic_data_10_minute[epic] = [] 124 | # 125 | # offer_average = sum(difference_offer)/len(difference_offer) 126 | # bid_average = sum(difference_bid)/len(difference_bid) 127 | # 128 | # # we have gone long we should now short 129 | # if (bid_average > 0 and offer_average> 0): 130 | # sell_level = high 131 | # elif (bid_average < 0 and offer_average < 0): 132 | # buy_level = low 133 | # 134 | # # instead here we are using bid/offer 135 | # 136 | # if (sell_level == None) and (buy_level == None): 137 | # return None 138 | # 139 | # signals_levels = { 140 | # "SELL": sell_level, 141 | # "BUY": buy_level 142 | # } 143 | # 144 | # return signals_levels 145 | # 146 | # def finding_lows_highs(self, data, reset = False): 147 | # 148 | # bid = data["snapshot"]["bid"] 149 | # offer = data["snapshot"]["offer"] 150 | # 151 | # if reset: 152 | # epic = data["instrument"]["epic"] 153 | # object_dict = self.map_epic_data_10_minute[epic][-1] 154 | # object_dict["snapshot"]["high"] = self.high 155 | # object_dict["snapshot"]["low"] = self.low 156 | # self.map_epic_data_10_minute[epic][-1] = object_dict 157 | # # start looking at the new interval 158 | # if self.high == None or reset: 159 | # self.high = offer 160 | # if self.low == None or reset: 161 | # self.low = bid 162 | # 163 | # if bid < self.low: 164 | # self.low = bid 165 | # if offer > self.high: 166 | # self.high = offer 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /Linked_to_biggest_previous_day_difference_in_price/adding_realtime_IG_data_to_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | IG Markets REST API sample with Python 6 | 2015 FemtoTrader 7 | """ 8 | 9 | from trading_ig import IGService 10 | from trading_ig.config import config 11 | import logging 12 | # format to 13 | # # from folder.file import class 14 | # from getting_instrument_based_data.navigate_tree import NavigateTree 15 | 16 | logger = logging.getLogger(__name__) 17 | logger.setLevel(logging.DEBUG) 18 | 19 | # if you need to cache to DB your requests 20 | from datetime import timedelta 21 | import requests_cache 22 | import time 23 | import os 24 | import json 25 | import pandas as pd 26 | 27 | 28 | counter = -1 29 | ig_service = None 30 | 31 | 32 | 33 | def login(): 34 | expire_after = timedelta(hours=1) 35 | session = requests_cache.CachedSession( 36 | cache_name='cache', backend='sqlite', expire_after=expire_after 37 | ) 38 | api_key = increment_api_key() 39 | 40 | global ig_service 41 | 42 | # no cache 43 | ig_service = IGService( 44 | config.username, config.password, api_key, config.acc_type 45 | ) 46 | ig_service.create_session() 47 | 48 | 49 | 50 | def main(): 51 | 52 | login() 53 | 54 | date = "2020-12-10_2021-02-10" 55 | # date = "2020-09-10_2020-12-10" 56 | time_interval = "5Min" 57 | paths = [ 58 | 59 | # "diff_from_morning_minus_afternoon_2020-12-01_2020-12-02_1Min", 60 | # "diff_from_morning_minus_afternoon_2020-12-02_2020-12-03_1Min", 61 | # "diff_from_morning_minus_afternoon_2020-12-03_2020-12-04_1Min", 62 | # "diff_from_morning_minus_afternoon_2020-12-04_2020-12-05_1Min", 63 | # "diff_from_morning_minus_afternoon_2020-12-05_2020-12-06_1Min", 64 | # "diff_from_morning_minus_afternoon_2020-12-06_2020-12-07_1Min", 65 | # "diff_from_morning_minus_afternoon_2020-12-07_2020-12-08_1Min", 66 | # "diff_from_morning_minus_afternoon_2020-12-08_2020-12-09_1Min", 67 | # "diff_from_morning_minus_afternoon_2020-12-09_2020-12-10_1Min", 68 | # "diff_from_morning_minus_afternoon_2020-12-10_2020-12-11_1Min", 69 | # "diff_from_morning_minus_afternoon_2020-12-11_2020-12-12_1Min", 70 | # "diff_from_morning_minus_afternoon_2020-12-14_2020-12-15_1Min", 71 | # "diff_from_morning_minus_afternoon_2020-12-15_2020-12-16_1Min", 72 | # "diff_from_morning_minus_afternoon_2020-12-16_2020-12-17_1Min", 73 | # "diff_from_morning_minus_afternoon_2020-12-17_2020-12-18_1Min", 74 | # "diff_from_morning_minus_afternoon_2020-12-18_2020-12-19_1Min", 75 | # "diff_from_morning_minus_afternoon_2020-12-21_2020-12-22_1Min", 76 | # "diff_from_morning_minus_afternoon_" + date + "_" + time_interval 77 | "diff_from_start_minus_end_" + date + "_" + time_interval 78 | ] 79 | 80 | for path in paths: 81 | get_data(path, date, time_interval) 82 | 83 | 84 | 85 | def get_data(file_name, date, time_interval): 86 | 87 | path = r"D:\Stock_Analysis\IG_Data_Fixing\Results\morning_afternoon_diffs\\"+file_name+".csv" 88 | dataframe = pd.read_csv(path) 89 | dataframe.rename(columns={"Unnamed: 0": "Datetime"}, inplace=True) 90 | Instrument_Data = dataframe.set_index("Datetime").T 91 | 92 | histroical_path_location = "D:\Data\IG_Instrument\historical_data\\" + time_interval + "\\" + date 93 | 94 | holding_list = [] 95 | 96 | for index in range(Instrument_Data.index.size): 97 | # save the data 98 | try: 99 | 100 | 101 | name = Instrument_Data.iloc[index].name 102 | epic = name.split("_ID_")[1] 103 | data = get_details_about_epic(epic) 104 | # get the magin requirement from here --------------------------------------------------------------------------------------------- 105 | data = json.loads(json.dumps(data)) 106 | # 107 | # map_of_items = { 108 | # "value" : data["instrument"]["marginFactor"], 109 | # "unit" : data["instrument"]["marginFactorUnit"]} 110 | # 111 | # difference_required = map_of_items["value"] 112 | # # otherwise the unit is POINTS 113 | # if map_of_items["unit"] == "PERCENTAGE": 114 | # difference_required = difference_required / 100 115 | # 116 | # difference_required * current_price 117 | temp = data["instrument"].copy() 118 | temp.update(data["dealingRules"]) 119 | temp.update(data["snapshot"]) 120 | temp["file_name"] = name 121 | temp["diff_score_across_time"] = Instrument_Data[Instrument_Data.columns[0]].iloc[index] 122 | 123 | 124 | whole_file_location = os.path.join(histroical_path_location, name) 125 | historical_data = pd.read_csv(whole_file_location, header=[0, 1], index_col=0) 126 | historical_data.index = pd.to_datetime(historical_data.index) 127 | 128 | bid = historical_data.iloc[0]["bid"]["Close"] 129 | ask = historical_data.iloc[0]["ask"]["Close"] 130 | spread = ask - bid 131 | 132 | temp["spread"] = spread 133 | temp["average"] = (bid + ask) / 2.0 134 | temp["diff_high-low"] = historical_data["bid"]["High"].max() - historical_data["bid"]["Low"].min() 135 | # could divide by zero and cause an error but would be caught by try and except clause 136 | temp["percent_spread-hl"] = (temp["spread"] / temp["diff_high-low"] * 100) 137 | 138 | 139 | holding_list.append(temp) 140 | 141 | dataframe = pd.DataFrame(holding_list) 142 | 143 | dataframe.to_csv("D:\Stock_Analysis\IG_Data_Fixing\Results\morn_after_diffs_instrument_data_added\\"+file_name+"_instrument_data_added.csv") 144 | 145 | except Exception as e: 146 | print(e) 147 | 148 | 149 | def get_details_about_epic(epic): 150 | global ig_service 151 | while(True): 152 | try: 153 | map_of_data = ig_service.fetch_market_by_epic(epic) 154 | return map_of_data 155 | except Exception as e: 156 | print(e) 157 | login() 158 | 159 | 160 | def increment_api_key(): 161 | key = "" 162 | global counter 163 | flag = True 164 | while (flag): 165 | try: 166 | counter += 1 167 | # has 12000 api keys 168 | fp = open("D:\Stock_Analysis\ig-markets-api-python-library-master\generate_api_keys\IG_api_keys_raw.txt") 169 | for i, line in enumerate(fp): 170 | if i == counter: 171 | key = line.split("\n")[0] 172 | flag = False 173 | break 174 | 175 | fp.close() 176 | except: 177 | counter = -1 178 | 179 | return key 180 | 181 | 182 | 183 | if __name__ == '__main__': 184 | main() 185 | -------------------------------------------------------------------------------- /predefined_functions/algo_ten_minute.py: -------------------------------------------------------------------------------- 1 | from trading_ig.config import config 2 | import logging 3 | 4 | logger = logging.getLogger(__name__) 5 | logger.setLevel(logging.DEBUG) 6 | 7 | # if you need to cache to DB your requests 8 | from datetime import timedelta 9 | import requests_cache 10 | from getting_realtime_data.data_retrieval import Data_Retrieval 11 | from sending_orders.order_management import Order_Management 12 | from management_of_position.position_management import Position_Management 13 | from predefined_functions.initialisation import Initialisation 14 | from get_data.get_market_data import Get_Market_Data 15 | import time 16 | from datetime import datetime, timedelta 17 | from predefined_functions.defined_functionality import Defined_Functionality 18 | import pandas 19 | import traceback 20 | 21 | 22 | class Algo0: 23 | def __init__(self): 24 | logging.basicConfig(level=logging.INFO) 25 | self.df = Defined_Functionality() 26 | 27 | # list_of_epics = ['IX.D.DOW.DAILY.IP'] 28 | list_of_epics = ['CS.D.EURUSD.TODAY.IP'] 29 | 30 | self.df.set_epics_to_look_for(epic_list=list_of_epics) 31 | 32 | self.map_epic_data_10_minute={} 33 | for epic in list_of_epics: 34 | self.map_epic_data_10_minute[epic] = [] 35 | 36 | 37 | self.first_timestamp = None 38 | self.high = None 39 | self.low = None 40 | 41 | def setup(self): 42 | self.df.initialise_connection() 43 | time.sleep(2) 44 | self.df.get_market_data() 45 | self.df.update_stop_level_bands() 46 | 47 | 48 | def run(self): 49 | 50 | while(True): 51 | try: 52 | self.setup() 53 | 54 | for epic in self.map_epic_data_10_minute.keys(): 55 | signals_and_levels = self.signal_generation(epic=epic) 56 | self.create_orders(epic=epic, signals_levels=signals_and_levels) 57 | 58 | except Exception as e: 59 | print(e, " error in the looping for the defined_functionality") 60 | traceback.print_exc() 61 | 62 | 63 | def create_orders(self, epic, signals_levels): 64 | if signals_levels == None: 65 | return 66 | key = None 67 | if signals_levels["BUY"] != None: 68 | key = "BUY" 69 | elif signals_levels["SELL"] != None: 70 | key = "SELL" 71 | 72 | self.df.cancel_orders_by_epic(epic=epic) 73 | position = self.df.find_open_position_by_epic(epic=epic) 74 | if isinstance(position,pandas.core.series.Series): 75 | print("position already exists", position) 76 | return position 77 | 78 | order = self.df.create_working_order_at_point(epic=epic, direction=key,price_order_level=signals_levels[key]) 79 | return order 80 | 81 | 82 | def signal_generation(self, epic): 83 | signals_levels = None 84 | # minute_10 = 60 * 10 85 | minute_10 = 60 * 10 86 | datetime_now = datetime.now() 87 | data = None 88 | if (self.first_timestamp != None): 89 | difference = (datetime_now - self.first_timestamp) 90 | data = self.df.get_market_data(epic=epic) 91 | self.finding_lows_highs(data=data) 92 | 93 | if (difference.seconds > minute_10): 94 | data = self.df.get_market_data(epic=epic) 95 | self.first_timestamp = datetime_now 96 | self.map_epic_data_10_minute[epic].append(data) 97 | self.finding_lows_highs(data=data, reset=True) 98 | 99 | else: 100 | data = self.df.get_market_data(epic=epic) 101 | self.first_timestamp = datetime_now 102 | 103 | self.map_epic_data_10_minute[epic].append(data) 104 | self.finding_lows_highs(data=data) 105 | 106 | if len(self.map_epic_data_10_minute[epic]) > 4: 107 | self.map_epic_data_10_minute[epic].pop(0) 108 | 109 | 110 | sell_level = None 111 | buy_level = None 112 | 113 | difference_bid = [] 114 | difference_offer = [] 115 | difference_low = [] 116 | difference_high = [] 117 | 118 | object_epic_data = self.map_epic_data_10_minute[epic][0] 119 | bid = object_epic_data["snapshot"]["bid"] 120 | offer = object_epic_data["snapshot"]["offer"] 121 | high = object_epic_data["snapshot"]["high"] 122 | low = object_epic_data["snapshot"]["low"] 123 | 124 | for i in range(1, len(self.map_epic_data_10_minute[epic])): 125 | 126 | object_epic_data = self.map_epic_data_10_minute[epic][i] 127 | bid = object_epic_data["snapshot"]["bid"] - bid 128 | offer = object_epic_data["snapshot"]["offer"] - offer 129 | high = object_epic_data["snapshot"]["high"] - high 130 | low = object_epic_data["snapshot"]["low"] - low 131 | 132 | difference_bid.append(bid) 133 | difference_offer.append(offer) 134 | difference_low.append(low) 135 | difference_high.append(high) 136 | # the high/low becomes the levels we enter orders at 137 | bid = object_epic_data["snapshot"]["bid"] 138 | offer = object_epic_data["snapshot"]["offer"] 139 | high = object_epic_data["snapshot"]["high"] 140 | low = object_epic_data["snapshot"]["low"] 141 | 142 | self.map_epic_data_10_minute[epic] = [] 143 | 144 | offer_average = sum(difference_offer)/len(difference_offer) 145 | bid_average = sum(difference_bid)/len(difference_bid) 146 | 147 | # we have gone long we should now short 148 | if (bid_average > 0 and offer_average> 0): 149 | sell_level = high 150 | elif (bid_average < 0 and offer_average < 0): 151 | buy_level = low 152 | 153 | # instead here we are using bid/offer 154 | 155 | if (sell_level == None) and (buy_level == None): 156 | return None 157 | 158 | signals_levels = { 159 | "SELL": sell_level, 160 | "BUY": buy_level 161 | } 162 | 163 | return signals_levels 164 | 165 | def finding_lows_highs(self, data, reset = False): 166 | 167 | bid = data["snapshot"]["bid"] 168 | offer = data["snapshot"]["offer"] 169 | 170 | if reset: 171 | epic = data["instrument"]["epic"] 172 | object_dict = self.map_epic_data_10_minute[epic][-1] 173 | object_dict["snapshot"]["high"] = self.high 174 | object_dict["snapshot"]["low"] = self.low 175 | self.map_epic_data_10_minute[epic][-1] = object_dict 176 | # start looking at the new interval 177 | if self.high == None or reset: 178 | self.high = offer 179 | if self.low == None or reset: 180 | self.low = bid 181 | 182 | if bid < self.low: 183 | self.low = bid 184 | if offer > self.high: 185 | self.high = offer 186 | 187 | 188 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /tests/test_ig_service.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | integration tests 6 | """ 7 | 8 | import pandas as pd 9 | import requests 10 | # import requests_cache 11 | from datetime import datetime, timedelta 12 | import six 13 | import time 14 | 15 | # import pprint 16 | 17 | import trading_ig 18 | from trading_ig import IGService 19 | from trading_ig.utils import remove 20 | from trading_ig.config import config 21 | 22 | """ 23 | Environment variables must be set using 24 | 25 | export IG_SERVICE_USERNAME="" 26 | export IG_SERVICE_PASSWORD="" 27 | export IG_SERVICE_API_KEY="" 28 | export IG_SERVICE_ACC_TYPE="DEMO" # LIVE / DEMO 29 | export IG_SERVICE_ACC_NUMBER="" 30 | 31 | """ 32 | 33 | CACHE_NAME = "cache" 34 | 35 | remove(CACHE_NAME) 36 | 37 | 38 | def test_ig_service(): 39 | 40 | delay_for_ig = 5 41 | 42 | def wait(delay): 43 | print( 44 | "Wait %s s to avoid 'error.public-api.exceeded-account-allowance'" % delay 45 | ) 46 | time.sleep(delay) 47 | 48 | # session_cached = requests_cache.CachedSession( 49 | # cache_name=CACHE_NAME, backend="sqlite", expire_after=timedelta(hours=1) 50 | # ) 51 | session_not_cached = requests.Session() 52 | 53 | # for i, session in enumerate([session_cached, session_cached, session_not_cached]): 54 | for i, session in enumerate([session_not_cached]): 55 | 56 | # pp = pprint.PrettyPrinter(indent=4) 57 | 58 | assert isinstance(trading_ig.__version__, six.string_types) 59 | 60 | ig_service = IGService( 61 | config.username, config.password, config.api_key, config.acc_type, session 62 | ) 63 | 64 | ig_service.create_session() 65 | 66 | print("%d - fetch_accounts" % i) 67 | response = ig_service.fetch_accounts() 68 | preferred = response.loc[response["preferred"] == True] 69 | assert all(preferred["balance"] > 0) 70 | 71 | print("") 72 | 73 | print("fetch_account_activity_by_period") 74 | response = ig_service.fetch_account_activity_by_period(10000) 75 | print(response) 76 | assert isinstance(response, pd.DataFrame) 77 | 78 | print("") 79 | 80 | print("fetch_transaction_history_by_type_and_period") 81 | response = ig_service.fetch_transaction_history_by_type_and_period(10000, "ALL") 82 | print(response) 83 | assert isinstance(response, pd.DataFrame) 84 | 85 | wait(delay_for_ig) 86 | print("") 87 | 88 | print("fetch_open_positions") 89 | response = ig_service.fetch_open_positions() 90 | print(response) 91 | assert isinstance(response, pd.DataFrame) 92 | 93 | print("") 94 | 95 | print("fetch_working_orders") 96 | response = ig_service.fetch_working_orders() 97 | print(response) 98 | assert isinstance(response, pd.DataFrame) 99 | 100 | print("") 101 | 102 | print("fetch_top_level_navigation_nodes") 103 | response = ig_service.fetch_top_level_navigation_nodes() 104 | print(response) # dict with nodes and markets 105 | assert isinstance(response, dict) 106 | market_id = response["nodes"]["id"].iloc[0] 107 | 108 | print("") 109 | 110 | print("fetch_client_sentiment_by_instrument") 111 | response = ig_service.fetch_client_sentiment_by_instrument(market_id) 112 | print(response) 113 | assert isinstance(response, dict) 114 | 115 | print("") 116 | 117 | # print("fetch_related_client_sentiment_by_instrument") 118 | # response = ig_service.fetch_related_client_sentiment_by_instrument(market_id) 119 | # print(response) 120 | # assert isinstance(response, pd.DataFrame) 121 | 122 | print("") 123 | 124 | print("fetch_sub_nodes_by_node") 125 | node = market_id 126 | response = ig_service.fetch_sub_nodes_by_node(node) 127 | print(response) 128 | assert isinstance(response["markets"], pd.DataFrame) 129 | assert isinstance(response["nodes"], pd.DataFrame) 130 | 131 | print("") 132 | wait(delay_for_ig) 133 | 134 | print("fetch_all_watchlists") 135 | response = ig_service.fetch_all_watchlists() 136 | print(response) 137 | assert isinstance(response, pd.DataFrame) 138 | watchlist_id = response["id"].iloc[0] # u'Popular Markets' 139 | 140 | print("") 141 | 142 | print("fetch_watchlist_markets") 143 | response = ig_service.fetch_watchlist_markets(watchlist_id) 144 | print(response) 145 | assert isinstance(response, pd.DataFrame) 146 | # epic = 'CS.D.EURUSD.MINI.IP' 147 | # epic = u'IX.D.CAC.IDF.IP' 148 | epic = response["epic"].iloc[0] 149 | 150 | print("") 151 | 152 | print("fetch_market_by_epic") 153 | response = ig_service.fetch_market_by_epic(epic) 154 | print(response) 155 | # pp.pprint(response) 156 | assert isinstance(response, dict) 157 | 158 | print("") 159 | 160 | print("search_markets") 161 | search_term = "EURUSD" 162 | # search_term = 'SPY' 163 | response = ig_service.search_markets(search_term) 164 | print(response) 165 | assert isinstance(response, pd.DataFrame) 166 | 167 | print("") 168 | wait(delay_for_ig) 169 | 170 | print("fetch_historical_prices_by_epic_and_num_points") 171 | 172 | # epic = 'CS.D.EURUSD.MINI.IP' 173 | # epic = 'IX.D.ASX.IFM.IP' # US 500 (SPY) 174 | # epic = 'IX.D.ASX.IFM.IP' # US (SPY) - mini 175 | # MINUTE, MINUTE_2, MINUTE_3, MINUTE_5, MINUTE_10, MINUTE_15, 176 | # MINUTE_30, HOUR, HOUR_2, HOUR_3, HOUR_4, DAY, WEEK, MONTH 177 | # resolution = 'HOUR' 178 | # http://pandas.pydata.org/pandas-docs/stable/timeseries.html#dateoffset-objects 179 | resolution = "H" 180 | num_points = 10 181 | response = ig_service.fetch_historical_prices_by_epic_and_num_points( 182 | epic, resolution, num_points 183 | ) 184 | print(response) 185 | # print(response['prices']['price']) 186 | # print(response['prices']['price']['ask']) 187 | # print(response['prices']['volume']) 188 | assert isinstance(response["allowance"], dict) 189 | # assert(isinstance(response['prices']['volume'], pd.Series)) 190 | # assert(isinstance(response['prices']['price'], pd.Panel)) 191 | assert isinstance(response["prices"], pd.DataFrame) 192 | 193 | print("") 194 | wait(delay_for_ig) 195 | 196 | print("fetch_historical_prices_by_epic_and_date_range") 197 | end_date = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0) 198 | start_date = end_date - timedelta(days=3) 199 | response = ig_service.fetch_historical_prices_by_epic_and_date_range( 200 | epic, resolution, start_date, end_date 201 | ) 202 | print(response) 203 | assert isinstance(response["allowance"], dict) 204 | # assert(isinstance(response['prices']['volume'], pd.Series)) 205 | # assert(isinstance(response['prices']['price'], pd.Panel)) 206 | assert isinstance(response["prices"], pd.DataFrame) 207 | 208 | print("") 209 | wait(delay_for_ig) 210 | 211 | remove(CACHE_NAME) 212 | -------------------------------------------------------------------------------- /sending_orders/order_management.py: -------------------------------------------------------------------------------- 1 | from trading_ig import IGService 2 | from trading_ig.config import config 3 | import logging 4 | 5 | logger = logging.getLogger(__name__) 6 | logger.setLevel(logging.INFO) 7 | 8 | # if you need to cache to DB your requests 9 | from datetime import timedelta 10 | import requests_cache 11 | 12 | from predefined_functions.initialisation import Initialisation 13 | 14 | class Order_Management(): 15 | def __init__(self): 16 | logging.basicConfig(level=logging.INFO) 17 | self.log = logging.getLogger(__name__) 18 | # set object and then set connection 19 | self.initial = Initialisation() 20 | self.initialise_connection() 21 | 22 | def initialise_connection(self): 23 | self.ig_service = self.initial.initialise_connection() 24 | self.ig_service.create_session() 25 | 26 | # limit orders 27 | def create_working_order(self, direction, epic, size, price, stop_distance,limit_distance,force_open=False): 28 | currency_code = "GBP" 29 | direction = direction 30 | epic = epic 31 | expiry = "DFB" 32 | if force_open == True: 33 | guaranteed_stop = False 34 | else: 35 | guaranteed_stop = True 36 | # entering price 37 | level = price 38 | # Pound per point size 39 | size = size 40 | time_in_force = "GOOD_TILL_CANCELLED" 41 | # LIMIT orders are now STOP 42 | order_type = "STOP" 43 | limit_distance = limit_distance 44 | stop_distance = stop_distance 45 | 46 | # currency_code = "GBP" 47 | # direction = "SELL" 48 | # epic = "CS.D.BITCOIN.TODAY.IP" 49 | # expiry = "DFB" 50 | # guaranteed_stop = False 51 | # # entering price 52 | # level = 13109 53 | # # Pound per point size 54 | # size = 0.50 55 | # time_in_force = "GOOD_TILL_CANCELLED" 56 | # order_type = "LIMIT" 57 | # limit_distance = 4000.0 58 | # stop_distance = 160.0 59 | 60 | # """Creates an OTC working order""" 61 | 62 | try: 63 | response = self.ig_service.create_working_order( 64 | currency_code=currency_code, 65 | direction=direction, 66 | epic=epic, 67 | expiry=expiry, 68 | guaranteed_stop=guaranteed_stop, 69 | level=level, 70 | size=size, 71 | time_in_force=time_in_force, 72 | order_type=order_type, 73 | limit_distance=limit_distance, 74 | stop_distance=stop_distance, 75 | force_open=force_open 76 | ) 77 | 78 | return response 79 | except Exception as e: 80 | self.log.info(str(e) + " error occurred when creating a working order") 81 | return None 82 | 83 | # market orders 84 | def create_open_position(self, direction, epic, size, limit_distance, stop_distance, force_open): 85 | currency_code = "GBP" 86 | direction = direction 87 | epic = epic 88 | expiry = "DFB" 89 | # no matter what you are doing force open always has to be True other wise stop losses do not work 90 | force_open = force_open 91 | if force_open: 92 | guaranteed_stop = False 93 | else: 94 | guaranteed_stop = True 95 | 96 | stop_distance = stop_distance 97 | size = size 98 | trailing_stop = False 99 | trailing_stop_increment = None 100 | trailing_stop_distance = None 101 | time_in_force = "FILL_OR_KILL" 102 | order_type = "MARKET" 103 | limit_distance = limit_distance 104 | 105 | try: 106 | response = self.ig_service.create_open_position( 107 | currency_code=currency_code, 108 | direction=direction, 109 | epic=epic, 110 | expiry=expiry, 111 | # no matter what you are doing force open always has to be True other wise stop losses do not work 112 | force_open=True, 113 | guaranteed_stop=guaranteed_stop, 114 | stop_distance=stop_distance, 115 | size=size, 116 | trailing_stop=trailing_stop, 117 | trailing_stop_increment=trailing_stop_increment, 118 | # trailing_stop_distance = trailing_stop_distance, 119 | # time_in_force=time_in_force, 120 | order_type=order_type, 121 | limit_distance=limit_distance) 122 | 123 | return response 124 | except Exception as e: 125 | self.log.info(str(e) + " error occurred when opening a position") 126 | return None 127 | 128 | # market orders to close positions 129 | def close_open_position(self, position, size): 130 | # set randomly 131 | try: 132 | direction = "BUY" 133 | position_direction = position["direction"] 134 | if position_direction == "BUY": 135 | direction = "SELL" 136 | 137 | deal_id = position["dealId"] 138 | order_type = "MARKET" 139 | size = size 140 | 141 | response = self.ig_service.close_open_position( 142 | deal_id=deal_id, 143 | direction=direction, 144 | order_type=order_type, 145 | size=size) 146 | 147 | return response 148 | except Exception as e: 149 | self.log.info(str(e) + " error occurred when closing position") 150 | return None 151 | 152 | def delete_working_order(self, deal_id): 153 | try: 154 | deal_id = deal_id 155 | response = self.ig_service.delete_working_order(deal_id) 156 | return response 157 | except Exception as e: 158 | self.log.info(str(e) + " error occurred when deleting working order") 159 | return None 160 | 161 | 162 | def update_position(self, limit_level, stop_level, deal_id, guaranteed_stop): 163 | limit_level = limit_level 164 | guaranteed_stop = guaranteed_stop 165 | stop_level=stop_level 166 | deal_id=deal_id 167 | trailing_stop = False 168 | trailing_stop_distance = None 169 | trailing_stop_increment = None 170 | 171 | try: 172 | 173 | response = self.ig_service.update_open_position( 174 | limit_level=limit_level, 175 | stop_level=stop_level, 176 | # guaranteed_stop=guaranteed_stop, 177 | deal_id =deal_id, 178 | # trailing_stop=trailing_stop, 179 | # trailing_stop_distance=trailing_stop_distance, 180 | # trailing_stop_increment=trailing_stop_increment 181 | ) 182 | 183 | return response 184 | 185 | except Exception as e: 186 | self.log.info(str(e) + " error occurred when updating position or maybe the order is no longer open") 187 | return None 188 | 189 | def get_open_positions(self): 190 | while(True): 191 | try: 192 | return self.ig_service.fetch_open_positions() 193 | except Exception as e: 194 | self.log.info(str(e) + " error occurred when getting open positions") 195 | # resets the connection 196 | self.initialise_connection() 197 | 198 | 199 | def get_working_orders(self): 200 | while(True): 201 | try: 202 | return self.ig_service.fetch_working_orders() 203 | except Exception as e: 204 | self.log.info(str(e) + " error occurred when getting working orders") 205 | self.initialise_connection() 206 | -------------------------------------------------------------------------------- /management_of_position/position_management.py: -------------------------------------------------------------------------------- 1 | from trading_ig import IGService 2 | from trading_ig.config import config 3 | import logging 4 | 5 | logger = logging.getLogger(__name__) 6 | logger.setLevel(logging.DEBUG) 7 | 8 | # if you need to cache to DB your requests 9 | from datetime import timedelta 10 | import requests_cache 11 | 12 | import time 13 | import json 14 | import math 15 | import pandas as pd 16 | from predefined_functions.initialisation import Initialisation 17 | 18 | class Position_Management(): 19 | def __init__(self): 20 | # set object then connection 21 | self.initial = Initialisation() 22 | self.initialise_connection() 23 | self.initialise_data() 24 | 25 | def initialise_connection(self): 26 | self.ig_service = self.initial.initialise_connection() 27 | 28 | def initialise_data(self): 29 | # this should change to be more dynamic 30 | # self.instrument_data = pd.read_csv("D:/Data/IG_Data/instruments_new_filtered.csv") 31 | # self.instrument_data.drop("Unnamed: 0", axis=1, inplace=True) 32 | pass 33 | 34 | def initialise(self): 35 | logging.basicConfig(level=logging.DEBUG) 36 | 37 | expire_after = timedelta(hours=1) 38 | session = requests_cache.CachedSession( 39 | cache_name='cache', backend='sqlite', expire_after=expire_after 40 | ) 41 | # set expire_after=None if you don't want cache expiration 42 | # set expire_after=0 if you don't want to cache queries 43 | 44 | # config = IGServiceConfig() 45 | 46 | # no cache 47 | self.ig_service = IGService( 48 | config.username, config.password, config.api_key, config.acc_type 49 | ) 50 | # if you want to globally cache queries 51 | # ig_service = IGService(config.username, config.password, config.api_key, config.acc_type, session) 52 | self.ig_service.create_session() 53 | 54 | def get_margin_min_distance_from_position_stop(self, dealing_rules, current_price, guaranteed_stop): 55 | # for controlled risk, guaranteed stop loss thing - keep to this one - worst case scenario - 56 | if guaranteed_stop: 57 | map_of_items = dealing_rules["minControlledRiskStopDistance"] 58 | else: 59 | #normal stop loss 60 | map_of_items = dealing_rules["minNormalStopOrLimitDistance"] 61 | 62 | # single_row = self.instrument_data[self.instrument_data["epic"] == epic] 63 | # the mam produces back the actual value and not the dataframe 64 | # map_of_items = json.loads(single_row["minControlledRiskStopDistance"].max()) 65 | 66 | difference_required = map_of_items["value"] 67 | # otherwise the unit is POINTS 68 | if map_of_items["unit"] == "PERCENTAGE": 69 | difference_required = difference_required / 100 70 | return (difference_required)*current_price 71 | 72 | return difference_required 73 | 74 | def get_margin_min_max_distance_from_position_limit(self, dealing_rules, current_price, min_limit_stop): 75 | # for controlled risk, guaranteed stop loss thing - keep to this one - worst case scenario 76 | if min_limit_stop: 77 | map_of_items = dealing_rules["minNormalStopOrLimitDistance"] 78 | else: 79 | map_of_items = dealing_rules["maxStopOrLimitDistance"] 80 | 81 | # single_row = self.instrument_data[self.instrument_data["epic"] == epic] 82 | # the mam produces back the actual value and not the dataframe 83 | # map_of_items = json.loads(single_row["minControlledRiskStopDistance"].max()) 84 | 85 | difference_required = map_of_items["value"] 86 | # otherwise the unit is POINTS 87 | if map_of_items["unit"] == "PERCENTAGE": 88 | difference_required = difference_required / 100 89 | return (difference_required)*current_price 90 | 91 | return difference_required 92 | 93 | 94 | def is_new_levels_better_and_generate(self, direction,stop_distance, current_price, entered_price, limit_distance, local, old_stop_level_price=None): 95 | stop_level = 0 96 | limit_level = 0 97 | # going short 98 | if direction == "SELL": 99 | # unlikely as we would always have a stop loss 100 | if old_stop_level_price == None: 101 | # have to do this as the stop level might not work spread moving too quickly 102 | stop_level = current_price + (stop_distance * 10) 103 | limit_level = entered_price - limit_distance 104 | 105 | return stop_level, limit_level 106 | 107 | # can't do this as the price might miss the stop loss 108 | # -------------------------------------------------------------------------------- 109 | # # setting the stop price at the entry point - as we are in profit 110 | # elif (current_price < entered_price) and (old_stop_level_price > entered_price): 111 | # return entered_price, None 112 | # -------------------------------------------------------------------------------- 113 | 114 | # get the distance between the edge that we can place the stop loss and the old stop loss and meet it half way 115 | """ 116 | This way you stop loss will that edge very closely 117 | """ 118 | 119 | stop_loss_edge = current_price + stop_distance 120 | half_distance = (old_stop_level_price - stop_loss_edge)/2.0 121 | stop_level = current_price + half_distance 122 | # stop loss is being missed on exchange increasing value 123 | if old_stop_level_price > (stop_level+0.1): 124 | return stop_level , None 125 | 126 | return None 127 | else: 128 | 129 | # put the stop loss at the entered price 130 | if (old_stop_level_price == None) : 131 | stop_level = current_price - (stop_distance * 10) 132 | limit_level = entered_price + limit_distance 133 | 134 | return stop_level, limit_level 135 | # # we are in profit - put the stop loss on the entered price 136 | # --------------------------------------------------------------------------------- 137 | # elif (current_price > entered_price) and (old_stop_level_price < entered_price): 138 | # return entered_price, None 139 | # --------------------------------------------------------------------------------- 140 | # get the distance between the edge that we can place the stop loss and the old stop loss and meet it half way 141 | """ 142 | This way you stop loss will that edge very closely 143 | """ 144 | stop_loss_edge = current_price - stop_distance 145 | half_distance = (stop_loss_edge - old_stop_level_price)/2.0 146 | stop_level = current_price - half_distance 147 | # stop_loss is missing on exchange 148 | if old_stop_level_price < (stop_level - 0.1): 149 | return stop_level, None 150 | 151 | return None 152 | 153 | # generated stop loss levels (numbers, not really implemented) 154 | def generate_levels_if_none_exists(self, direction, stop_distance, current_price, entered_price, limit_distance): 155 | stop_level = 0 156 | limit_level = 0 157 | if direction == "SELL": 158 | stop_level = stop_distance + current_price 159 | limit_level = entered_price - limit_distance 160 | return stop_level,limit_level 161 | 162 | else: 163 | stop_level = stop_distance - current_price 164 | limit_level = entered_price + limit_distance 165 | return stop_level,limit_level 166 | -------------------------------------------------------------------------------- /tests/data/historic_prices_v2.json: -------------------------------------------------------------------------------- 1 | { 2 | "prices": [ 3 | { 4 | "snapshotTime": "2020/10/09 05:00:00", 5 | "openPrice": { 6 | "bid": 1915.5, 7 | "ask": 1916.1, 8 | "lastTraded": null 9 | }, 10 | "closePrice": { 11 | "bid": 1936.3, 12 | "ask": 1936.3, 13 | "lastTraded": null 14 | }, 15 | "highPrice": { 16 | "bid": 1936.4, 17 | "ask": 1937.0, 18 | "lastTraded": null 19 | }, 20 | "lowPrice": { 21 | "bid": 1910.2, 22 | "ask": 1910.8, 23 | "lastTraded": null 24 | }, 25 | "lastTradedVolume": 138981 26 | }, 27 | { 28 | "snapshotTime": "2020/10/11 05:00:00", 29 | "openPrice": { 30 | "bid": 1926.2, 31 | "ask": 1926.2, 32 | "lastTraded": null 33 | }, 34 | "closePrice": { 35 | "bid": 1933.2, 36 | "ask": 1933.8, 37 | "lastTraded": null 38 | }, 39 | "highPrice": { 40 | "bid": 1939.1, 41 | "ask": 1939.7, 42 | "lastTraded": null 43 | }, 44 | "lowPrice": { 45 | "bid": 1926.2, 46 | "ask": 1926.2, 47 | "lastTraded": null 48 | }, 49 | "lastTradedVolume": 25069 50 | }, 51 | { 52 | "snapshotTime": "2020/10/12 05:00:00", 53 | "openPrice": { 54 | "bid": 1933.4, 55 | "ask": 1934.0, 56 | "lastTraded": null 57 | }, 58 | "closePrice": { 59 | "bid": 1916.0, 60 | "ask": 1916.6, 61 | "lastTraded": null 62 | }, 63 | "highPrice": { 64 | "bid": 1937.7, 65 | "ask": 1938.3, 66 | "lastTraded": null 67 | }, 68 | "lowPrice": { 69 | "bid": 1915.1, 70 | "ask": 1915.7, 71 | "lastTraded": null 72 | }, 73 | "lastTradedVolume": 117691 74 | }, 75 | { 76 | "snapshotTime": "2020/10/13 05:00:00", 77 | "openPrice": { 78 | "bid": 1915.9, 79 | "ask": 1916.5, 80 | "lastTraded": null 81 | }, 82 | "closePrice": { 83 | "bid": 1898.5, 84 | "ask": 1899.1, 85 | "lastTraded": null 86 | }, 87 | "highPrice": { 88 | "bid": 1930.2, 89 | "ask": 1930.8, 90 | "lastTraded": null 91 | }, 92 | "lowPrice": { 93 | "bid": 1884.8, 94 | "ask": 1885.4, 95 | "lastTraded": null 96 | }, 97 | "lastTradedVolume": 182974 98 | }, 99 | { 100 | "snapshotTime": "2020/10/14 05:00:00", 101 | "openPrice": { 102 | "bid": 1898.6, 103 | "ask": 1899.2, 104 | "lastTraded": null 105 | }, 106 | "closePrice": { 107 | "bid": 1901.5, 108 | "ask": 1902.1, 109 | "lastTraded": null 110 | }, 111 | "highPrice": { 112 | "bid": 1917.2, 113 | "ask": 1917.8, 114 | "lastTraded": null 115 | }, 116 | "lowPrice": { 117 | "bid": 1895.4, 118 | "ask": 1896.0, 119 | "lastTraded": null 120 | }, 121 | "lastTradedVolume": 136388 122 | }, 123 | { 124 | "snapshotTime": "2020/10/15 05:00:00", 125 | "openPrice": { 126 | "bid": 1901.4, 127 | "ask": 1902.0, 128 | "lastTraded": null 129 | }, 130 | "closePrice": { 131 | "bid": 1909.8, 132 | "ask": 1910.4, 133 | "lastTraded": null 134 | }, 135 | "highPrice": { 136 | "bid": 1914.9, 137 | "ask": 1915.5, 138 | "lastTraded": null 139 | }, 140 | "lowPrice": { 141 | "bid": 1892.6, 142 | "ask": 1893.2, 143 | "lastTraded": null 144 | }, 145 | "lastTradedVolume": 149438 146 | }, 147 | { 148 | "snapshotTime": "2020/10/16 05:00:00", 149 | "openPrice": { 150 | "bid": 1909.9, 151 | "ask": 1910.5, 152 | "lastTraded": null 153 | }, 154 | "closePrice": { 155 | "bid": 1902.9, 156 | "ask": 1902.9, 157 | "lastTraded": null 158 | }, 159 | "highPrice": { 160 | "bid": 1918.4, 161 | "ask": 1919.0, 162 | "lastTraded": null 163 | }, 164 | "lowPrice": { 165 | "bid": 1900.9, 166 | "ask": 1901.5, 167 | "lastTraded": null 168 | }, 169 | "lastTradedVolume": 96594 170 | }, 171 | { 172 | "snapshotTime": "2020/10/18 05:00:00", 173 | "openPrice": { 174 | "bid": 1906.4, 175 | "ask": 1906.4, 176 | "lastTraded": null 177 | }, 178 | "closePrice": { 179 | "bid": 1903.6, 180 | "ask": 1904.2, 181 | "lastTraded": null 182 | }, 183 | "highPrice": { 184 | "bid": 1906.4, 185 | "ask": 1906.9, 186 | "lastTraded": null 187 | }, 188 | "lowPrice": { 189 | "bid": 1900.0, 190 | "ask": 1900.6, 191 | "lastTraded": null 192 | }, 193 | "lastTradedVolume": 14182 194 | }, 195 | { 196 | "snapshotTime": "2020/10/19 05:00:00", 197 | "openPrice": { 198 | "bid": 1903.5, 199 | "ask": 1904.1, 200 | "lastTraded": null 201 | }, 202 | "closePrice": { 203 | "bid": 1903.7, 204 | "ask": 1904.3, 205 | "lastTraded": null 206 | }, 207 | "highPrice": { 208 | "bid": 1922.5, 209 | "ask": 1923.1, 210 | "lastTraded": null 211 | }, 212 | "lowPrice": { 213 | "bid": 1896.5, 214 | "ask": 1897.1, 215 | "lastTraded": null 216 | }, 217 | "lastTradedVolume": 123866 218 | }, 219 | { 220 | "snapshotTime": "2020/10/20 05:00:00", 221 | "openPrice": { 222 | "bid": 1903.6, 223 | "ask": 1904.2, 224 | "lastTraded": null 225 | }, 226 | "closePrice": { 227 | "bid": 1909.4, 228 | "ask": 1909.4, 229 | "lastTraded": null 230 | }, 231 | "highPrice": { 232 | "bid": 1917.4, 233 | "ask": 1918.0, 234 | "lastTraded": null 235 | }, 236 | "lowPrice": { 237 | "bid": 1899.7, 238 | "ask": 1900.3, 239 | "lastTraded": null 240 | }, 241 | "lastTradedVolume": 103956 242 | } 243 | ], 244 | "instrumentType": "COMMODITIES", 245 | "allowance": { 246 | "remainingAllowance": 9698, 247 | "totalAllowance": 10000, 248 | "allowanceExpiry": 273984 249 | } 250 | } -------------------------------------------------------------------------------- /getting_historical_data/rest_ig_get_historical_data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | IG Markets REST API sample with Python 6 | 2015 FemtoTrader 7 | """ 8 | 9 | from trading_ig import IGService 10 | from trading_ig.config import config 11 | import logging 12 | import pandas as pd 13 | import os 14 | 15 | logger = logging.getLogger(__name__) 16 | logger.setLevel(logging.DEBUG) 17 | 18 | # if you need to cache to DB your requests 19 | from datetime import datetime, timedelta 20 | import requests_cache 21 | import math 22 | import numpy as np 23 | import time 24 | 25 | counter = -1 26 | 27 | 28 | def login(): 29 | expire_after = timedelta(hours=1) 30 | session = requests_cache.CachedSession( 31 | cache_name='cache', backend='sqlite', expire_after=expire_after 32 | ) 33 | api_key = increment_api_key() 34 | 35 | # no cache 36 | ig_service = IGService( 37 | config.username, config.password, api_key, config.acc_type 38 | ) 39 | ig_service.create_session() 40 | 41 | return ig_service 42 | 43 | 44 | def main(): 45 | logging.basicConfig(level=logging.DEBUG) 46 | # 47 | # expire_after = timedelta(hours=1) 48 | # session = requests_cache.CachedSession( 49 | # cache_name='cache', backend='sqlite', expire_after=expire_after 50 | # ) 51 | # # set expire_after=None if you don't want cache expiration 52 | # # set expire_after=0 if you don't want to cache queries 53 | # 54 | # #config = IGServiceConfig() 55 | # 56 | # # no cache 57 | # ig_service = IGService( 58 | # config.username, config.password, config.api_key, config.acc_type 59 | # ) 60 | # 61 | # # if you want to globally cache queries 62 | # #ig_service = IGService(config.username, config.password, config.api_key, config.acc_type, session) 63 | # 64 | # ig_service.create_session() 65 | 66 | # accounts = ig_service.fetch_accounts() 67 | # print("accounts:\n%s" % accounts) 68 | 69 | # account_info = ig_service.switch_account(config.acc_number, False) 70 | # print(account_info) 71 | 72 | # open_positions = ig_service.fetch_open_positions() 73 | # print("open_positions:\n%s" % open_positions) 74 | 75 | ig_service = login() 76 | 77 | print("") 78 | 79 | # working_orders = ig_service.fetch_working_orders() 80 | # print("working_orders:\n%s" % working_orders) 81 | 82 | print("") 83 | 84 | # strimming data ---------------------- 85 | # instrument_data = pd.read_csv("D:/Data/IG_Data/instruments.csv") 86 | # instrument_data.drop("Unnamed: 0", axis=1, inplace=True) 87 | # 88 | # instrument_data["average"] = (instrument_data["bid"] + instrument_data["offer"]) / 2 89 | # instrument_data["margin_in_pounds_required"] = instrument_data["average"] * 0.5 * instrument_data["margin"] 90 | # 91 | # # Cheap_Shares = instrument_data[(instrument_data["margin_in_pounds_required"] < 2) 92 | # # & (instrument_data["location"].str.contains("Shares - ") 93 | # # & (instrument_data["margin_in_pounds_required"] > 1))] 94 | # 95 | # # Cheap_Shares = instrument_data[(instrument_data["margin_in_pounds_required"] < 10) 96 | # # & (instrument_data["location"].str.contains("Shares - ") 97 | # # & (instrument_data["average"] > 1))] 98 | # 99 | # # gets rid of small averages 100 | # # gets rid of small averages 101 | # list_of_items_to_remove = [] 102 | # for index in range(instrument_data.index.size): 103 | # # print(instrument_data["average"].iloc[index]) 104 | # 105 | # if (instrument_data["average"].iloc[index] < 0.5) or (math.isnan(instrument_data["average"].iloc[index]) or ( 106 | # instrument_data["location"].str.contains("Option").iloc[index])): 107 | # list_of_items_to_remove.append(instrument_data.index[index]) 108 | # 109 | # for item in list_of_items_to_remove: 110 | # instrument_data.drop(index=item, axis=0, inplace=True) 111 | # strimming data ---------------------- 112 | 113 | instrument = pd.read_csv("D:/Stock_Analysis/ig-markets-api-python-library-master/Data/SpreadBetting/Instruments.csv") 114 | instrument.drop("Unnamed: 0", axis=1, inplace=True) 115 | 116 | list_of_epics = instrument["epic"].to_list() 117 | list_names = instrument["name"].to_list() 118 | 119 | 120 | resolution = '5Min' 121 | 122 | 123 | for date_counter in range(1): 124 | 125 | # start_date = "2020-11-%02d" % date_counter 126 | # end_date = "2020-11-%02d" % (date_counter + 1) 127 | start_date = "2021-05-10" 128 | end_date = "2021-05-12" 129 | 130 | for index in range(len(list_of_epics)): 131 | 132 | epic = list_of_epics[index] 133 | name = list_names[index] 134 | # epic = 'CS.D.EURUSD.MINI.IP' 135 | # epic = 'IX.D.ASX.IFM.IP' # US (SPY) - mini 136 | 137 | # resolution = 'D' 138 | # see from pandas.tseries.frequencies import to_offset 139 | # resolution = 'H' 140 | # resolution = '1Min' 141 | 142 | num_points = 9000 143 | print(name) 144 | response = None 145 | 146 | while (True): 147 | try: 148 | # response = ig_service.fetch_historical_prices_by_epic_and_num_points( 149 | # epic, resolution, num_points 150 | # ) 151 | response = ig_service.fetch_historical_prices_by_epic_and_date_range( 152 | epic=epic, resolution=resolution, start_date=start_date, end_date=end_date 153 | ) 154 | break 155 | except Exception as e: 156 | print(e, " there was not data available") 157 | 158 | if (str(e) == "error.public-api.exceeded-account-historical-data-allowance") or (str(e) == "error.security.client-token-invalid") or (str(e) == "error.security.generic") or (str(e) == "error.public-api.exceeded-api-key-allowance"): 159 | ig_service = login() 160 | continue 161 | else: 162 | print(e, "exception not know") 163 | 164 | break 165 | 166 | if response == None: 167 | continue 168 | 169 | print(response) 170 | print("\n \n") 171 | data_frame_of_prices = response["prices"] 172 | save_to_file(data_frame_of_prices, name,resolution, start_date, end_date,epic) 173 | 174 | 175 | 176 | 177 | def save_to_file(dataframe, name, resolution, start_date, end_date, epic): 178 | 179 | try: 180 | name = name.replace("/", "-") 181 | directory = r"D:/Data/IG_Instrument/historical_data/"+resolution+"/"+start_date+"_"+end_date 182 | if not os.path.exists(directory): 183 | try: 184 | semi_directory = r"D:/Data/IG_Instrument/historical_data/"+resolution 185 | os.mkdir(semi_directory) 186 | except Exception as e: 187 | print(e) 188 | 189 | os.mkdir(directory) 190 | 191 | full_path = directory+"/"+name+"_"+resolution+"_ID_"+epic+"_ID_.csv" 192 | 193 | dataframe.to_csv(full_path) 194 | except Exception as e: 195 | print("failed to write to file " + str(e)) 196 | 197 | 198 | 199 | def increment_api_key(): 200 | key = "" 201 | global counter 202 | flag = True 203 | while (flag): 204 | try: 205 | counter += 1 206 | # has 12000 api keys 207 | fp = open("D:/Stock_Analysis/ig-markets-api-python-library-master/generate_api_keys/IG_api_keys_raw.txt") 208 | for i, line in enumerate(fp): 209 | if i == counter: 210 | key = line.split("\n")[0] 211 | flag = False 212 | break 213 | 214 | fp.close() 215 | except: 216 | counter = -1 217 | 218 | return key 219 | 220 | 221 | if __name__ == '__main__': 222 | main() 223 | -------------------------------------------------------------------------------- /Data/CFDs/instrument_details_SECTORS.csv: -------------------------------------------------------------------------------- 1 | bid,delayTime,epic,expiry,high,instrumentName,instrumentType,lotSize,low,marketStatus,netChange,offer,otcTradeable,percentageChange,scalingFactor,streamingPricesAvailable,updateTime,updateTimeUTC1286.9,0,KB.D.OZTELE.IFD.IP,-,1295.3,Australia 200 Communications,SECTORS,10,1272.5,TRADEABLE,20.4,1292.1,True,1.61,1,True,-1705000,00:31:35 2 | 1286.9,0,KB.D.OZTELE.IFM.IP,-,1295.3,Australia 200 Communications (A$2 Mini Contract),SECTORS,2,1272.5,TRADEABLE,20.4,1292.1,True,1.61,1,True,-1705000,00:31:35 3 | 2734.2,0,KB.D.OZCOND.IFD.IP,-,2748.3,Consumer Disc.,SECTORS,10,2721.3,TRADEABLE,13.7,2745.2,True,0.5,1,True,-1675000,00:32:05 4 | 2734.2,0,KB.D.OZCOND.IFM.IP,-,2748.3,Consumer Disc. (A$2 Mini Contract),SECTORS,2,2721.3,TRADEABLE,13.7,2745.2,True,0.5,1,True,-1675000,00:32:05 5 | 13169.3,0,KB.D.OZCONSUM.IFD.IP,-,13235.0,Consumer Staples,SECTORS,10,13140.5,TRADEABLE,50.7,13222.1,True,0.39,1,True,-1675000,00:32:05 6 | 13169.3,0,KB.D.OZCONSUM.IFM.IP,-,13235.0,Consumer Staples (A$2 Mini Contract),SECTORS,2,13140.5,TRADEABLE,50.7,13222.1,True,0.39,1,True,-1675000,00:32:05 7 | 11540.6,0,KB.D.OZENER.IFD.IP,-,11612.7,Energy,SECTORS,10,11466.0,TRADEABLE,37.1,11586.8,True,0.32,1,True,-1675000,00:32:05 8 | 11540.6,0,KB.D.OZENER.IFM.IP,-,11612.7,Energy (A$2 Mini Contract),SECTORS,2,11466.0,TRADEABLE,37.1,11586.8,True,0.32,1,True,-1675000,00:32:05 9 | 6061.5,0,KB.D.OZFINL.IFD.IP,-,6091.0,Financials,SECTORS,10,6041.5,TRADEABLE,5.4,6085.7,True,0.09,1,True,-1675000,00:32:05 10 | 6061.5,0,KB.D.OZFINL.IFM.IP,-,6091.0,Financials (A$2 Mini Contract),SECTORS,2,6041.5,TRADEABLE,5.4,6085.7,True,0.09,1,True,-1675000,00:32:05 11 | 41228.1,0,KB.D.OZHEALTH.IFD.IP,-,41421.6,Health,SECTORS,10,40984.4,TRADEABLE,3.0,41393.3,True,0.01,1,True,-1675000,00:32:05 12 | 41228.1,0,KB.D.OZHEALTH.IFM.IP,-,41421.6,Health (A$2 Mini Contract),SECTORS,2,40984.4,TRADEABLE,3.0,41393.3,True,0.01,1,True,-1675000,00:32:05 13 | 7175.8,0,KB.D.OZINDU.IFD.IP,-,7218.0,Industrials,SECTORS,10,7171.7,TRADEABLE,1.1,7204.6,True,0.02,1,True,-1675000,00:32:05 14 | 7175.8,0,KB.D.OZINDU.IFM.IP,-,7218.0,Industrials (A$2 Mini Contract),SECTORS,2,7171.7,TRADEABLE,1.1,7204.6,True,0.02,1,True,-1675000,00:32:05 15 | 1451.3,0,KB.D.OZIT.IFD.IP,-,1457.1,IT,SECTORS,10,1443.1,TRADEABLE,9.2,1457.1,True,0.64,1,True,-1645000,00:32:35 16 | 1451.3,0,KB.D.OZIT.IFM.IP,-,1457.1,IT (A$2 Mini Contract),SECTORS,2,1443.1,TRADEABLE,9.2,1457.1,True,0.64,1,True,-1645000,00:32:35 17 | 13584.7,0,KB.D.OZMATR.IFD.IP,-,13656.1,Materials,SECTORS,10,13526.1,TRADEABLE,111.5,13639.1,True,0.83,1,True,-1615000,00:33:05 18 | 13584.7,0,KB.D.OZMATR.IFM.IP,-,13656.1,Materials (A$2 Mini Contract),SECTORS,2,13526.1,TRADEABLE,111.5,13639.1,True,0.83,1,True,-1615000,00:33:05 19 | 8147.4,0,KB.D.OZUTILI.IFD.IP,-,8200.5,Utilities,SECTORS,10,8112.1,TRADEABLE,89.9,8180.0,True,1.11,1,True,-1615000,00:33:05 20 | 8147.4,0,KB.D.OZUTILI.IFM.IP,-,8200.5,Utilities (A$2 Mini Contract),SECTORS,2,8112.1,TRADEABLE,89.9,8180.0,True,1.11,1,True,-1615000,00:33:05 21 | 5092.0,0,KB.D.AERO.CASH.IP,-,5116.0,Aerospace and Defence,SECTORS,10,5072.0,EDITS_ONLY,-2.0,5102.0,True,-0.04,1,True,55800000,16:30:00 22 | 3689.0,0,KB.D.BANKS.CASH.IP,-,3706.0,Banks,SECTORS,10,3672.0,EDITS_ONLY,6.0,3697.0,True,0.15,1,True,56129000,16:35:29 23 | 3689.0,0,KB.D.BANKS.IFM.IP,-,3706.0,Banks (£2 Mini Contract),SECTORS,2,3672.0,EDITS_ONLY,6.0,3697.0,True,0.15,1,True,56129000,16:35:29 24 | 25369.0,0,KB.D.DRINKS.CASH.IP,-,25528.0,Beverages,SECTORS,10,25107.0,EDITS_ONLY,317.0,25419.0,True,1.26,1,True,56126000,16:35:26 25 | 13006.0,0,KB.D.CHEMS.CASH.IP,-,12999.0,Chemicals,SECTORS,10,12767.0,EDITS_ONLY,255.0,13032.0,True,2.0,1,True,56128000,16:35:28 26 | 6906.0,0,KB.D.BUILD.CASH.IP,-,6933.0,Construction and Materials,SECTORS,10,6817.0,EDITS_ONLY,169.0,6920.0,True,2.5,1,True,56125000,16:35:25 27 | 7717.0,0,KB.D.ELECTY.CASH.IP,-,7834.0,Electricity,SECTORS,10,7736.0,EDITS_ONLY,-89.0,7732.0,True,-1.14,1,True,56129000,16:35:29 28 | 8622.0,0,KB.D.EE.CASH.IP,-,8644.0,Electronic and Electrical Equipment,SECTORS,10,8451.0,EDITS_ONLY,162.0,8639.0,True,1.92,1,True,56115000,16:35:15 29 | 10573.0,0,KB.D.INV.CASH.IP,-,10579.0,Equity Investment Instruments,SECTORS,10,10519.0,EDITS_ONLY,62.0,10595.0,True,0.59,1,True,56437000,16:40:37 30 | 12119.0,0,KB.D.SPECFINAN.CASH.IP,-,12156.0,Financial Services,SECTORS,10,11999.0,EDITS_ONLY,168.0,12143.0,True,1.41,1,True,56130000,16:35:30 31 | 2222.0,0,KB.D.PHONES.CASH.IP,-,2253.0,Fixed Line Telecommunications,SECTORS,10,2222.0,EDITS_ONLY,-29.0,2227.0,True,-1.27,1,True,56121000,16:35:21 32 | 3870.0,0,KB.D.FDR.CASH.IP,-,3894.0,Food and Drug Retailers,SECTORS,10,3863.0,EDITS_ONLY,-1.0,3878.0,True,-0.03,1,True,56126000,16:35:26 33 | 7931.0,0,KB.D.FOOD.CASH.IP,-,7953.0,Food Producers,SECTORS,10,7775.0,EDITS_ONLY,123.0,7947.0,True,1.58,1,True,56129000,16:35:29 34 | 5108.0,0,KB.D.WATER.CASH.IP,-,5157.0,Gas Water and Multiutilities,SECTORS,10,5106.0,EDITS_ONLY,0.0,5118.0,True,-0.0,1,True,56121000,16:35:21 35 | 6220.0,0,KB.D.GINDU.CASH.IP,-,6265.0,General Industrials,SECTORS,10,6188.0,EDITS_ONLY,15.0,6232.0,True,0.24,1,True,56127000,16:35:27 36 | 6220.0,0,KB.D.GINDU.IFM.IP,-,6265.0,General Industrials (£2 Mini Contract),SECTORS,10,6188.0,EDITS_ONLY,15.0,6232.0,True,0.24,1,True,56127000,16:35:27 37 | 2331.0,0,KB.D.RETAIL.CASH.IP,-,2347.0,General Retailers,SECTORS,10,2327.0,EDITS_ONLY,10.0,2336.0,True,0.43,1,True,56130000,16:35:30 38 | 2331.0,0,KB.D.RETAIL.IFM.IP,-,2347.0,General Retailers (£2 Mini Contract),SECTORS,2,2327.0,EDITS_ONLY,10.0,2336.0,True,0.43,1,True,56130000,16:35:30 39 | 8213.0,0,KB.D.HEALTH.CASH.IP,-,8262.0,Health Care Equipment and Services,SECTORS,10,8127.0,EDITS_ONLY,2.0,8229.0,True,0.02,1,True,56129000,16:35:29 40 | 17005.0,0,KB.D.HSEHLD.CASH.IP,-,17096.0,Household Goods and Home Construction,SECTORS,10,16928.0,EDITS_ONLY,135.0,17039.0,True,0.8,1,True,55800000,16:30:00 41 | 20844.0,0,KB.D.MID250.CASH.IP,-,20885.0,FTSE Mid 250,SECTORS,10,20697.0,EDITS_ONLY,162.0,20886.0,True,0.78,1,True,56437000,16:40:37 42 | 20844.0,0,KB.D.MID250.IFM.IP,-,20885.0,FTSE Mid 250 (£2 Mini Contract),SECTORS,2,20697.0,EDITS_ONLY,162.0,20886.0,True,0.78,1,True,56437000,16:40:37 43 | 5768.0,0,KB.D.TK.CASH.IP,-,5789.0,Techmark,SECTORS,10,5727.0,EDITS_ONLY,34.0,5779.0,True,0.59,1,True,56129000,16:35:29 44 | 5768.0,0,KB.D.TK.IFM.IP,-,5789.0,Techmark (£2 Mini Contract),SECTORS,2,5727.0,EDITS_ONLY,34.0,5779.0,True,0.59,1,True,56129000,16:35:29 45 | 13104.0,0,KB.D.ENGINE.CASH.IP,-,13166.0,Industrial Engineering,SECTORS,10,12966.0,EDITS_ONLY,118.0,13130.0,True,0.91,1,True,56129000,16:35:29 46 | 2365.0,0,KB.D.BUS.CASH.IP,-,2383.0,Industrial Transportation,SECTORS,10,2317.0,EDITS_ONLY,56.0,2370.0,True,2.4,1,True,56118000,16:35:18 47 | 7538.0,0,KB.D.LIFE.CASH.IP,-,7570.0,Life Insurance,SECTORS,10,7484.0,EDITS_ONLY,23.0,7553.0,True,0.3,1,True,56125000,16:35:25 48 | 8810.0,0,KB.D.MEDIA.CASH.IP,-,8865.0,Media,SECTORS,10,8799.0,EDITS_ONLY,6.0,8828.0,True,0.07,1,True,56130000,16:35:30 49 | 18531.0,0,KB.D.MINING.CASH.IP,-,18595.0,Mining,SECTORS,10,18419.0,EDITS_ONLY,129.0,18568.0,True,0.7,1,True,56128000,16:35:28 50 | 18531.0,0,KB.D.MINING.IFM.IP,-,18595.0,Mining (£2 Mini Contract),SECTORS,2,18419.0,EDITS_ONLY,129.0,18568.0,True,0.7,1,True,56128000,16:35:28 51 | 3101.0,0,KB.D.INSURANCE.CASH.IP,-,3104.0,Non-life Insurance,SECTORS,10,3057.0,EDITS_ONLY,50.0,3107.0,True,1.65,1,True,56121000,16:35:21 52 | 8230.0,0,KB.D.OIL.CASH.IP,-,8368.0,Oil and Gas Producers,SECTORS,10,8225.0,EDITS_ONLY,-100.0,8246.0,True,-1.2,1,True,56115000,16:35:15 53 | 7953.0,0,KB.D.OILEQUIP.CASH.IP,-,8226.0,Oil Equipment and Services,SECTORS,10,7885.0,EDITS_ONLY,-100.0,7969.0,True,-1.24,1,True,56123000,16:35:23 54 | 39261.31,0,KB.D.PGOODS.CASH.IP,-,39517.4,Personal Goods,SECTORS,10,38776.49,EDITS_ONLY,328.9,39339.91,True,0.84,1,True,56124000,16:35:24 55 | 17554.0,0,KB.D.PHARMA.IFM.IP,-,17612.0,Pharmaceuticals (£2 Mini Contract),SECTORS,2,17352.0,EDITS_ONLY,92.0,17607.0,True,0.53,1,True,56128000,16:35:28 56 | 17563.0,0,KB.D.PHARMA.CASH.IP,-,17603.0,Pharmaceuticals and Biotechnology,SECTORS,10,17361.0,EDITS_ONLY,92.0,17598.0,True,0.53,1,True,56128000,16:35:28 57 | 3208.0,0,KB.D.REAL.CASH.IP,-,3224.0,Real Estate Investment Trusts,SECTORS,10,3179.0,EDITS_ONLY,24.0,3214.0,True,0.76,1,True,56130000,16:35:30 58 | 2172.0,0,KB.D.SOFT.CASH.IP,-,2183.0,Software and Computer Services,SECTORS,10,2145.0,EDITS_ONLY,12.0,2176.0,True,0.55,1,True,56126000,16:35:26 59 | 9316.0,0,KB.D.SUPPORT.CASH.IP,-,9346.0,Support Services,SECTORS,10,9186.0,EDITS_ONLY,78.0,9334.0,True,0.85,1,True,56126000,16:35:26 60 | 31627.0,0,KB.D.TOBACCO.CASH.IP,-,31971.0,Tobacco,SECTORS,10,31541.0,EDITS_ONLY,-203.0,31690.0,True,-0.64,1,True,56121000,16:35:21 61 | 31627.0,0,KB.D.TOBACCO.IFM.IP,-,31971.0,Tobacco (£2 Mini Contract),SECTORS,2,31541.0,EDITS_ONLY,-203.0,31690.0,True,-0.64,1,True,56121000,16:35:21 62 | 10108.0,0,KB.D.HOTELS.CASH.IP,-,10189.0,Travel and Leisure,SECTORS,10,10036.0,EDITS_ONLY,-169.0,10128.0,True,-1.64,1,True,56124000,16:35:24 63 | -------------------------------------------------------------------------------- /getting_realtime_data/data_retrieval.py: -------------------------------------------------------------------------------- 1 | import time 2 | import sys 3 | import traceback 4 | import logging 5 | import math 6 | 7 | from trading_ig import (IGService, IGStreamService) 8 | from trading_ig.config import config 9 | from trading_ig.lightstreamer import Subscription 10 | from predefined_functions.initialisation import Initialisation 11 | 12 | class Data_Retrieval: 13 | def __init__(self): 14 | logging.basicConfig(level=logging.INFO) 15 | self.log = logging.getLogger(__name__) 16 | self.ig_stream_service = [] 17 | self.data_map = {} 18 | self.initial = Initialisation() 19 | 20 | def initialise_connection(self, number_of_subscriptions): 21 | # logging.basicConfig(level=logging.DEBUG) 22 | for index in range(number_of_subscriptions): 23 | while(True): 24 | try: 25 | ig_service = self.initial.initialise_connection() 26 | 27 | self.ig_stream_service.append(IGStreamService(ig_service)) 28 | ig_session = self.ig_stream_service[index].create_session() 29 | self.accountId = config.acc_number 30 | self.ig_stream_service[index].connect(self.accountId) 31 | # it will automatically create the account connection 32 | break 33 | except Exception as e: 34 | print(e, " data retrieval error login") 35 | 36 | 37 | def restart_service(self): 38 | while(True): 39 | try: 40 | self.ig_stream_service.unsubscribe_all() 41 | self.initialise_connection() 42 | return 43 | except Exception as e: 44 | self.log.info(str(e) + " connection error") 45 | 46 | 47 | # market data based info 48 | def create_subscription_market_data(self, data): 49 | number_of_subscriptions = math.ceil(len(data)/30) 50 | if number_of_subscriptions > 38: 51 | raise Exception("your account could be blocked, too many subscriptions ") 52 | self.initialise_connection(number_of_subscriptions) 53 | list_of_epics_in_sets_30 = list(self.chunks(data, 30)) 54 | 55 | for index in range(len(list_of_epics_in_sets_30)): 56 | self.create_individual_subscription_market_data(list_of_epics_in_sets_30[index], index) 57 | 58 | 59 | def chunks(self,lst, n): 60 | """Yield successive n-sized chunks from lst.""" 61 | for i in range(0, len(lst), n): 62 | yield lst[i:i + n] 63 | 64 | 65 | def create_individual_subscription_market_data(self,data,index): 66 | # if len(self.ig_stream_service.ls_client._subscriptions) > 0: 67 | # #reset everything market data based 68 | # self.restart_service() 69 | 70 | subscription_holding = self.create_subscription_subPrice(data) 71 | self.ig_stream_service[index].ls_client.subscribe(subscription_holding) 72 | 73 | 74 | # account and trade based info 75 | def create_subscription_account(self): 76 | self.initialise_connection(1) 77 | subscription_holding = self.create_subscription_subAccount() 78 | self.ig_stream_service[0].ls_client.subscribe(subscription_holding) 79 | 80 | def create_subscription_trade(self): 81 | self.initialise_connection(1) 82 | subscription_holding = self.create_subscription_subTradeInfo() 83 | self.ig_stream_service[0].ls_client.subscribe(subscription_holding) 84 | 85 | 86 | # done like this for debugging purposes 87 | def register_subscription(self, subscription): 88 | sub_key_prices = self.ig_stream_service.ls_client.subscribe(subscription) 89 | return sub_key_prices 90 | 91 | 92 | 93 | # subscription functions 94 | def create_subscription_subAccount(self): 95 | 96 | subscription_account = Subscription( 97 | mode="MERGE", 98 | items=['ACCOUNT:' + self.accountId], 99 | fields=[ 100 | "AVAILABLE_CASH", 101 | "PNL", 102 | "PNL_LR", 103 | "PNL_NLR", 104 | "FUNDS", 105 | "MARGIN", 106 | "MARGIN_LR", 107 | "AVAILABLE_TO_DEAL", 108 | "EQUITY", 109 | "EQUITY_USED"], 110 | ) 111 | 112 | # #adapter="QUOTE_ADAPTER") 113 | 114 | # Adding the "on_balance_update" function to Subscription 115 | subscription_account.addlistener(self.on_account_update) 116 | return subscription_account 117 | 118 | def create_subscription_subTradeInfo(self): 119 | 120 | subscription_trade = Subscription( 121 | 122 | mode="DISTINCT", 123 | items=['TRADE:' + self.accountId], 124 | fields=[ 125 | "CONFIRMS", 126 | "OPU", 127 | "WOU"], 128 | ) 129 | 130 | subscription_trade.addlistener(self.on_trade_update) 131 | return subscription_trade 132 | 133 | def create_subscription_subPrice(self, epic_temp): 134 | # Making a new Subscription in MERGE mode 135 | epic_list = list.copy(epic_temp) 136 | for index in range(len(epic_list)): 137 | epic_list[index] = "L1:"+epic_list[index] 138 | 139 | subscription_prices = Subscription( 140 | mode="MERGE", 141 | items=epic_list, 142 | fields=["UPDATE_TIME", 143 | "BID", 144 | "OFFER", 145 | "CHANGE", 146 | "MARKET_STATE", 147 | "MID_OPEN", 148 | "HIGH", 149 | "LOW", 150 | "CHANGE", 151 | "CHANGE_PCT", 152 | "MARKET_DELAY"] 153 | ) 154 | # 155 | # CHANGE_PCT 156 | # UPDATE_TIME 157 | # MARKET_DELAY Delayed price (0=false, 1=true) 158 | # MARKET_STATE 159 | 160 | subscription_prices.addlistener(self.on_prices_update) 161 | return subscription_prices 162 | 163 | 164 | # function to catch update in events 165 | def on_prices_update(self, item_update): 166 | # print("price: %s " % item_update) 167 | name = item_update["name"].split(":")[1] 168 | 169 | if not name in self.data_map: 170 | self.data_map[name] = [] 171 | for items in item_update["values"]: 172 | try: 173 | item_update["values"][items] = float(item_update["values"][items]) 174 | except: 175 | pass 176 | 177 | self.data_map[name].append(item_update["values"]) 178 | 179 | if len(self.data_map[name]) > 20: 180 | # remove only keep the latest 20 items 181 | self.data_map[name] = self.data_map[name][-20:] 182 | 183 | 184 | # print("{stock_name:<19}: Time {UPDATE_TIME:<8} - " 185 | # "Bid {BID:>5} - Ask {OFFER:>5}".format( 186 | # stock_name=item_update["name"], **item_update["values"] 187 | # )) 188 | 189 | def on_account_update(self, balance_update): 190 | name = "account" 191 | if not name in self.data_map: 192 | self.data_map[name] = [] 193 | self.data_map[name].append(balance_update) 194 | 195 | if len(self.data_map[name]) > 20: 196 | # remove only keep the latest 20 items 197 | self.data_map[name] = self.data_map[name][-20:] 198 | 199 | # print("balance: %s " % balance_update) 200 | 201 | def on_trade_update(self, trade_update): 202 | name = "trade" 203 | if not name in self.data_map: 204 | self.data_map[name] = [] 205 | self.data_map[name].append(trade_update) 206 | 207 | if len(self.data_map[name]) > 20: 208 | # remove only keep the latest 20 items 209 | self.data_map[name] = self.data_map[name][-20:] 210 | 211 | # print("trade: %s " % trade_update) 212 | 213 | 214 | # get the latest data 215 | def get_market_data(self, epic): 216 | if epic in self.data_map: 217 | return self.data_map[epic][-1] 218 | 219 | def get_old_market_data(self, epic): 220 | if epic in self.data_map: 221 | if len(self.data_map[epic]) >= 19: 222 | return self.data_map[epic][0] 223 | 224 | def get_trade_data(self): 225 | if "trade" in self.data_map: 226 | return self.data_map["trade"][-1] 227 | else: 228 | return None 229 | 230 | def get_account_data(self): 231 | if "account" in self.data_map: 232 | return self.data_map["account"][-1] 233 | else: 234 | return None -------------------------------------------------------------------------------- /tests/data/historic_prices.json: -------------------------------------------------------------------------------- 1 | { 2 | "prices": [ 3 | { 4 | "snapshotTime": "2020/10/12 21:50:00", 5 | "snapshotTimeUTC": "2020-10-12T20:50:00", 6 | "openPrice": { 7 | "bid": 1926.4, 8 | "ask": 1927.0, 9 | "lastTraded": null 10 | }, 11 | "closePrice": { 12 | "bid": 1927.3, 13 | "ask": 1927.9, 14 | "lastTraded": null 15 | }, 16 | "highPrice": { 17 | "bid": 1927.7, 18 | "ask": 1928.3, 19 | "lastTraded": null 20 | }, 21 | "lowPrice": { 22 | "bid": 1926.4, 23 | "ask": 1927.0, 24 | "lastTraded": null 25 | }, 26 | "lastTradedVolume": 60 27 | }, 28 | { 29 | "snapshotTime": "2020/10/12 21:51:00", 30 | "snapshotTimeUTC": "2020-10-12T20:51:00", 31 | "openPrice": { 32 | "bid": 1927.4, 33 | "ask": 1928.0, 34 | "lastTraded": null 35 | }, 36 | "closePrice": { 37 | "bid": 1927.1, 38 | "ask": 1927.7, 39 | "lastTraded": null 40 | }, 41 | "highPrice": { 42 | "bid": 1927.4, 43 | "ask": 1928.0, 44 | "lastTraded": null 45 | }, 46 | "lowPrice": { 47 | "bid": 1926.7, 48 | "ask": 1927.3, 49 | "lastTraded": null 50 | }, 51 | "lastTradedVolume": 31 52 | }, 53 | { 54 | "snapshotTime": "2020/10/12 21:52:00", 55 | "snapshotTimeUTC": "2020-10-12T20:52:00", 56 | "openPrice": { 57 | "bid": 1927.2, 58 | "ask": 1927.8, 59 | "lastTraded": null 60 | }, 61 | "closePrice": { 62 | "bid": 1927.0, 63 | "ask": 1927.6, 64 | "lastTraded": null 65 | }, 66 | "highPrice": { 67 | "bid": 1927.2, 68 | "ask": 1927.8, 69 | "lastTraded": null 70 | }, 71 | "lowPrice": { 72 | "bid": 1927.0, 73 | "ask": 1927.6, 74 | "lastTraded": null 75 | }, 76 | "lastTradedVolume": 4 77 | }, 78 | { 79 | "snapshotTime": "2020/10/12 21:53:00", 80 | "snapshotTimeUTC": "2020-10-12T20:53:00", 81 | "openPrice": { 82 | "bid": 1927.1, 83 | "ask": 1927.7, 84 | "lastTraded": null 85 | }, 86 | "closePrice": { 87 | "bid": 1927.3, 88 | "ask": 1927.9, 89 | "lastTraded": null 90 | }, 91 | "highPrice": { 92 | "bid": 1927.5, 93 | "ask": 1928.1, 94 | "lastTraded": null 95 | }, 96 | "lowPrice": { 97 | "bid": 1927.1, 98 | "ask": 1927.7, 99 | "lastTraded": null 100 | }, 101 | "lastTradedVolume": 6 102 | }, 103 | { 104 | "snapshotTime": "2020/10/12 21:54:00", 105 | "snapshotTimeUTC": "2020-10-12T20:54:00", 106 | "openPrice": { 107 | "bid": 1927.4, 108 | "ask": 1928.0, 109 | "lastTraded": null 110 | }, 111 | "closePrice": { 112 | "bid": 1927.2, 113 | "ask": 1927.8, 114 | "lastTraded": null 115 | }, 116 | "highPrice": { 117 | "bid": 1927.4, 118 | "ask": 1928.0, 119 | "lastTraded": null 120 | }, 121 | "lowPrice": { 122 | "bid": 1927.2, 123 | "ask": 1927.8, 124 | "lastTraded": null 125 | }, 126 | "lastTradedVolume": 5 127 | }, 128 | { 129 | "snapshotTime": "2020/10/12 21:55:00", 130 | "snapshotTimeUTC": "2020-10-12T20:55:00", 131 | "openPrice": { 132 | "bid": 1927.3, 133 | "ask": 1927.9, 134 | "lastTraded": null 135 | }, 136 | "closePrice": { 137 | "bid": 1927.2, 138 | "ask": 1927.8, 139 | "lastTraded": null 140 | }, 141 | "highPrice": { 142 | "bid": 1927.3, 143 | "ask": 1927.9, 144 | "lastTraded": null 145 | }, 146 | "lowPrice": { 147 | "bid": 1927.1, 148 | "ask": 1927.7, 149 | "lastTraded": null 150 | }, 151 | "lastTradedVolume": 26 152 | }, 153 | { 154 | "snapshotTime": "2020/10/12 21:56:00", 155 | "snapshotTimeUTC": "2020-10-12T20:56:00", 156 | "openPrice": { 157 | "bid": 1927.0, 158 | "ask": 1927.6, 159 | "lastTraded": null 160 | }, 161 | "closePrice": { 162 | "bid": 1927.0, 163 | "ask": 1927.6, 164 | "lastTraded": null 165 | }, 166 | "highPrice": { 167 | "bid": 1927.1, 168 | "ask": 1927.7, 169 | "lastTraded": null 170 | }, 171 | "lowPrice": { 172 | "bid": 1927.0, 173 | "ask": 1927.6, 174 | "lastTraded": null 175 | }, 176 | "lastTradedVolume": 20 177 | }, 178 | { 179 | "snapshotTime": "2020/10/12 21:57:00", 180 | "snapshotTimeUTC": "2020-10-12T20:57:00", 181 | "openPrice": { 182 | "bid": 1926.8, 183 | "ask": 1927.4, 184 | "lastTraded": null 185 | }, 186 | "closePrice": { 187 | "bid": 1926.7, 188 | "ask": 1927.3, 189 | "lastTraded": null 190 | }, 191 | "highPrice": { 192 | "bid": 1926.9, 193 | "ask": 1927.5, 194 | "lastTraded": null 195 | }, 196 | "lowPrice": { 197 | "bid": 1926.7, 198 | "ask": 1927.3, 199 | "lastTraded": null 200 | }, 201 | "lastTradedVolume": 49 202 | }, 203 | { 204 | "snapshotTime": "2020/10/12 21:58:00", 205 | "snapshotTimeUTC": "2020-10-12T20:58:00", 206 | "openPrice": { 207 | "bid": 1926.8, 208 | "ask": 1927.4, 209 | "lastTraded": null 210 | }, 211 | "closePrice": { 212 | "bid": 1927.0, 213 | "ask": 1927.6, 214 | "lastTraded": null 215 | }, 216 | "highPrice": { 217 | "bid": 1927.0, 218 | "ask": 1927.6, 219 | "lastTraded": null 220 | }, 221 | "lowPrice": { 222 | "bid": 1926.7, 223 | "ask": 1927.3, 224 | "lastTraded": null 225 | }, 226 | "lastTradedVolume": 39 227 | }, 228 | { 229 | "snapshotTime": "2020/10/12 21:59:00", 230 | "snapshotTimeUTC": "2020-10-12T20:59:00", 231 | "openPrice": { 232 | "bid": 1926.9, 233 | "ask": 1927.5, 234 | "lastTraded": null 235 | }, 236 | "closePrice": { 237 | "bid": 1927.1, 238 | "ask": 1927.7, 239 | "lastTraded": null 240 | }, 241 | "highPrice": { 242 | "bid": 1927.1, 243 | "ask": 1927.7, 244 | "lastTraded": null 245 | }, 246 | "lowPrice": { 247 | "bid": 1926.9, 248 | "ask": 1927.5, 249 | "lastTraded": null 250 | }, 251 | "lastTradedVolume": 24 252 | } 253 | ], 254 | "instrumentType": "COMMODITIES", 255 | "metadata": { 256 | "allowance": { 257 | "remainingAllowance": 9644, 258 | "totalAllowance": 10000, 259 | "allowanceExpiry": 69976 260 | }, 261 | "size": 10, 262 | "pageData": { 263 | "pageSize": 20, 264 | "pageNumber": 1, 265 | "totalPages": 1 266 | } 267 | } 268 | } -------------------------------------------------------------------------------- /tests/data/historic_prices_num_points.json: -------------------------------------------------------------------------------- 1 | { 2 | "prices": [ 3 | { 4 | "snapshotTime": "2020/08/10 00:00:00", 5 | "snapshotTimeUTC": "2020-08-09T23:00:00", 6 | "openPrice": { 7 | "bid": 2028.0, 8 | "ask": 2028.0, 9 | "lastTraded": null 10 | }, 11 | "closePrice": { 12 | "bid": 1953.7, 13 | "ask": 1953.7, 14 | "lastTraded": null 15 | }, 16 | "highPrice": { 17 | "bid": 2060.5, 18 | "ask": 2061.1, 19 | "lastTraded": null 20 | }, 21 | "lowPrice": { 22 | "bid": 1874.3, 23 | "ask": 1874.9, 24 | "lastTraded": null 25 | }, 26 | "lastTradedVolume": 1196283 27 | }, 28 | { 29 | "snapshotTime": "2020/08/17 00:00:00", 30 | "snapshotTimeUTC": "2020-08-16T23:00:00", 31 | "openPrice": { 32 | "bid": 1949.8, 33 | "ask": 1949.8, 34 | "lastTraded": null 35 | }, 36 | "closePrice": { 37 | "bid": 1947.4, 38 | "ask": 1947.4, 39 | "lastTraded": null 40 | }, 41 | "highPrice": { 42 | "bid": 2023.8, 43 | "ask": 2024.4, 44 | "lastTraded": null 45 | }, 46 | "lowPrice": { 47 | "bid": 1916.4, 48 | "ask": 1917.0, 49 | "lastTraded": null 50 | }, 51 | "lastTradedVolume": 1171405 52 | }, 53 | { 54 | "snapshotTime": "2020/08/24 00:00:00", 55 | "snapshotTimeUTC": "2020-08-23T23:00:00", 56 | "openPrice": { 57 | "bid": 1947.0, 58 | "ask": 1947.0, 59 | "lastTraded": null 60 | }, 61 | "closePrice": { 62 | "bid": 1972.6, 63 | "ask": 1972.6, 64 | "lastTraded": null 65 | }, 66 | "highPrice": { 67 | "bid": 1986.6, 68 | "ask": 1987.2, 69 | "lastTraded": null 70 | }, 71 | "lowPrice": { 72 | "bid": 1908.2, 73 | "ask": 1908.8, 74 | "lastTraded": null 75 | }, 76 | "lastTradedVolume": 1128584 77 | }, 78 | { 79 | "snapshotTime": "2020/08/31 00:00:00", 80 | "snapshotTimeUTC": "2020-08-30T23:00:00", 81 | "openPrice": { 82 | "bid": 1974.9, 83 | "ask": 1974.9, 84 | "lastTraded": null 85 | }, 86 | "closePrice": { 87 | "bid": 1940.9, 88 | "ask": 1940.9, 89 | "lastTraded": null 90 | }, 91 | "highPrice": { 92 | "bid": 2000.4, 93 | "ask": 2001.0, 94 | "lastTraded": null 95 | }, 96 | "lowPrice": { 97 | "bid": 1921.7, 98 | "ask": 1922.3, 99 | "lastTraded": null 100 | }, 101 | "lastTradedVolume": 1005035 102 | }, 103 | { 104 | "snapshotTime": "2020/09/07 00:00:00", 105 | "snapshotTimeUTC": "2020-09-06T23:00:00", 106 | "openPrice": { 107 | "bid": 1934.3, 108 | "ask": 1934.3, 109 | "lastTraded": null 110 | }, 111 | "closePrice": { 112 | "bid": 1948.1, 113 | "ask": 1948.1, 114 | "lastTraded": null 115 | }, 116 | "highPrice": { 117 | "bid": 1974.8, 118 | "ask": 1975.4, 119 | "lastTraded": null 120 | }, 121 | "lowPrice": { 122 | "bid": 1911.7, 123 | "ask": 1912.3, 124 | "lastTraded": null 125 | }, 126 | "lastTradedVolume": 802470 127 | }, 128 | { 129 | "snapshotTime": "2020/09/14 00:00:00", 130 | "snapshotTimeUTC": "2020-09-13T23:00:00", 131 | "openPrice": { 132 | "bid": 1947.9, 133 | "ask": 1947.9, 134 | "lastTraded": null 135 | }, 136 | "closePrice": { 137 | "bid": 1957.1, 138 | "ask": 1957.1, 139 | "lastTraded": null 140 | }, 141 | "highPrice": { 142 | "bid": 1983.0, 143 | "ask": 1983.6, 144 | "lastTraded": null 145 | }, 146 | "lowPrice": { 147 | "bid": 1938.5, 148 | "ask": 1939.1, 149 | "lastTraded": null 150 | }, 151 | "lastTradedVolume": 834497 152 | }, 153 | { 154 | "snapshotTime": "2020/09/21 00:00:00", 155 | "snapshotTimeUTC": "2020-09-20T23:00:00", 156 | "openPrice": { 157 | "bid": 1962.1, 158 | "ask": 1962.1, 159 | "lastTraded": null 160 | }, 161 | "closePrice": { 162 | "bid": 1864.3, 163 | "ask": 1864.3, 164 | "lastTraded": null 165 | }, 166 | "highPrice": { 167 | "bid": 1962.6, 168 | "ask": 1963.2, 169 | "lastTraded": null 170 | }, 171 | "lowPrice": { 172 | "bid": 1851.0, 173 | "ask": 1852.0, 174 | "lastTraded": null 175 | }, 176 | "lastTradedVolume": 1116122 177 | }, 178 | { 179 | "snapshotTime": "2020/09/28 00:00:00", 180 | "snapshotTimeUTC": "2020-09-27T23:00:00", 181 | "openPrice": { 182 | "bid": 1866.3, 183 | "ask": 1866.3, 184 | "lastTraded": null 185 | }, 186 | "closePrice": { 187 | "bid": 1904.1, 188 | "ask": 1904.1, 189 | "lastTraded": null 190 | }, 191 | "highPrice": { 192 | "bid": 1923.2, 193 | "ask": 1923.8, 194 | "lastTraded": null 195 | }, 196 | "lowPrice": { 197 | "bid": 1851.4, 198 | "ask": 1852.0, 199 | "lastTraded": null 200 | }, 201 | "lastTradedVolume": 856763 202 | }, 203 | { 204 | "snapshotTime": "2020/10/05 00:00:00", 205 | "snapshotTimeUTC": "2020-10-04T23:00:00", 206 | "openPrice": { 207 | "bid": 1907.6, 208 | "ask": 1907.6, 209 | "lastTraded": null 210 | }, 211 | "closePrice": { 212 | "bid": 1936.3, 213 | "ask": 1936.3, 214 | "lastTraded": null 215 | }, 216 | "highPrice": { 217 | "bid": 1936.4, 218 | "ask": 1937.0, 219 | "lastTraded": null 220 | }, 221 | "lowPrice": { 222 | "bid": 1876.9, 223 | "ask": 1877.5, 224 | "lastTraded": null 225 | }, 226 | "lastTradedVolume": 728781 227 | }, 228 | { 229 | "snapshotTime": "2020/10/12 00:00:00", 230 | "snapshotTimeUTC": "2020-10-11T23:00:00", 231 | "openPrice": { 232 | "bid": 1926.2, 233 | "ask": 1926.2, 234 | "lastTraded": null 235 | }, 236 | "closePrice": { 237 | "bid": 1906.6, 238 | "ask": 1907.2, 239 | "lastTraded": null 240 | }, 241 | "highPrice": { 242 | "bid": 1939.1, 243 | "ask": 1939.7, 244 | "lastTraded": null 245 | }, 246 | "lowPrice": { 247 | "bid": 1884.8, 248 | "ask": 1885.4, 249 | "lastTraded": null 250 | }, 251 | "lastTradedVolume": 364914 252 | } 253 | ], 254 | "instrumentType": "COMMODITIES", 255 | "metadata": { 256 | "allowance": { 257 | "remainingAllowance": 9952, 258 | "totalAllowance": 10000, 259 | "allowanceExpiry": 565788 260 | }, 261 | "size": 10, 262 | "pageData": { 263 | "pageSize": 20, 264 | "pageNumber": 1, 265 | "totalPages": 1 266 | } 267 | } 268 | } -------------------------------------------------------------------------------- /predefined_functions/algo_catch_trends_from_different_markets.py: -------------------------------------------------------------------------------- 1 | from trading_ig.config import config 2 | import logging 3 | 4 | logger = logging.getLogger(__name__) 5 | logger.setLevel(logging.DEBUG) 6 | 7 | # if you need to cache to DB your requests 8 | from datetime import timedelta 9 | import requests_cache 10 | from getting_realtime_data.data_retrieval import Data_Retrieval 11 | from sending_orders.order_management import Order_Management 12 | from management_of_position.position_management import Position_Management 13 | from predefined_functions.initialisation import Initialisation 14 | from get_data.get_market_data import Get_Market_Data 15 | import time 16 | from datetime import datetime, timedelta 17 | from predefined_functions.defined_functionality import Defined_Functionality 18 | import pandas 19 | import traceback 20 | 21 | 22 | # the newest one where you make market order base on price movements 5 or more and try to catch the trend 23 | 24 | class Algo0: 25 | def __init__(self): 26 | logging.basicConfig(level=logging.INFO) 27 | self.df = Defined_Functionality() 28 | 29 | 30 | 31 | # list_of_epics = ['IX.D.DOW.DAILY.IP'] 32 | # list_of_epics = ['IX.D.SPTRD.DAILY.IP'] 33 | # list_of_epics = ['CS.D.EURUSD.TODAY.IP'] 34 | list_of_epics = [ 35 | 'IX.D.DOW.DAILY.IP', 36 | 'IX.D.SPTRD.DAILY.IP', 37 | 'IX.D.FTSE.DAILY.IP' 38 | ] 39 | 40 | self.df.set_epics_to_look_for(epic_list=list_of_epics) 41 | 42 | self.tradeable_epic = ['IX.D.DOW.DAILY.IP'] 43 | 44 | self.map_epic_data_minute = {} 45 | for epic in list_of_epics: 46 | self.map_epic_data_minute[epic] = [] 47 | 48 | self.first_timestamp = None 49 | self.high = None 50 | self.low = None 51 | 52 | def setup(self): 53 | self.df.initialise_connection() 54 | # not required as we are not trailing any losses 55 | # time.sleep(2) 56 | # self.df.get_market_data() 57 | # self.df.update_stop_level_bands() 58 | 59 | def run(self): 60 | 61 | while (True): 62 | try: 63 | self.setup() 64 | 65 | for epic in self.tradeable_epic: 66 | 67 | signals_and_levels = self.signal_generation(epic_list=self.map_epic_data_minute.keys()) 68 | position = self.create_position(signal=signals_and_levels, epic=epic) 69 | if position == "error": continue 70 | self.closing_incrments(position=position,signals=signals_and_levels) 71 | 72 | except Exception as e: 73 | print(e, " error in the looping for the defined_functionality") 74 | 75 | traceback.print_exc() 76 | 77 | 78 | 79 | 80 | def create_position(self, signal, epic): 81 | position = self.df.find_open_position_by_epic(epic=epic) 82 | 83 | if position == "error": return position 84 | if len(position) >= 1: return position 85 | if signal == None: return None 86 | 87 | key=None 88 | if signal["BUY"]: 89 | key = "BUY" 90 | elif signal["SELL"]: 91 | key = "SELL" 92 | 93 | if key == None: return None 94 | 95 | position = self.df.create_open_position(epic=epic, direction=key, size=0.5) 96 | return position 97 | 98 | 99 | def closing_incrments(self, position, signals): 100 | position = position[0] 101 | direction = position["position"]["direction"] 102 | epic = position["market"]["epic"] 103 | opening_price = position["position"]["openLevel"] 104 | 105 | data = self.df.get_market_data(epic=epic) 106 | bid = data["snapshot"]["bid"] 107 | offer = data["snapshot"]["offer"] 108 | 109 | spread = offer - bid 110 | 111 | boolean_close_buy = False 112 | boolean_close_sell = False 113 | 114 | if direction == "BUY": 115 | boolean_close_buy = opening_price < (bid - spread) 116 | 117 | elif direction == "SELL": 118 | boolean_close_sell = opening_price > (offer + spread) 119 | 120 | if boolean_close_buy or boolean_close_sell: 121 | closing_increment = self.df.close_position(size=0.01,position=position) 122 | return closing_increment 123 | return None 124 | 125 | 126 | 127 | def signal_generation(self, epic_list): 128 | signals_levels = None 129 | # minute_10 = 60 * 10 130 | # minute_10 = 60 131 | minute_10 = 6 132 | datetime_now = datetime.now() 133 | limit = 3 134 | data = None 135 | 136 | signal_matrix = {} 137 | 138 | capture_time = False 139 | 140 | for epic in epic_list: 141 | 142 | if (self.first_timestamp != None): 143 | difference = (datetime_now - self.first_timestamp) 144 | # appending data into df map_epic_data 145 | data = self.df.get_market_data(epic=epic) 146 | # self.finding_lows_highs(data=data) 147 | 148 | if (difference.seconds > minute_10): 149 | capture_time = True 150 | data = self.df.get_market_data(epic=epic) 151 | self.map_epic_data_minute[epic].append(data) 152 | # self.finding_lows_highs(data=data, reset=True) 153 | 154 | else: 155 | data = self.df.get_market_data(epic=epic) 156 | capture_time = True 157 | self.map_epic_data_minute[epic].append(data) 158 | # self.finding_lows_highs(data=data) 159 | 160 | if len(self.map_epic_data_minute[epic]) > limit: 161 | self.map_epic_data_minute[epic].pop(0) 162 | 163 | sell_level = None 164 | buy_level = None 165 | 166 | object_epic_data = self.map_epic_data_minute[epic][-1] 167 | bid = object_epic_data["snapshot"]["bid"] 168 | offer = object_epic_data["snapshot"]["offer"] 169 | high = object_epic_data["snapshot"]["high"] 170 | low = object_epic_data["snapshot"]["low"] 171 | 172 | object_epic_data = self.map_epic_data_minute[epic][-2] 173 | bid_second = object_epic_data["snapshot"]["bid"] 174 | offer_second = object_epic_data["snapshot"]["offer"] 175 | high_second = object_epic_data["snapshot"]["high"] 176 | low_second = object_epic_data["snapshot"]["low"] 177 | 178 | object_epic_data = self.map_epic_data_minute[epic][-3] 179 | bid_third = object_epic_data["snapshot"]["bid"] 180 | offer_third = object_epic_data["snapshot"]["offer"] 181 | high_third = object_epic_data["snapshot"]["high"] 182 | low_third = object_epic_data["snapshot"]["low"] 183 | # the price is going down there you should buy 184 | if offer_third > offer_second > offer: 185 | buy_level = 1 186 | # the price is going up therefore you should sell 187 | elif bid_third < bid_second < bid: 188 | sell_level = 1 189 | 190 | signal_matrix[epic] = { 191 | "SELL": sell_level, 192 | "BUY": buy_level 193 | } 194 | 195 | if capture_time: 196 | self.first_timestamp = datetime_now 197 | 198 | key = list(self.map_epic_data_minute.keys())[0] 199 | # because up above you remove one item from the list 200 | 201 | if (not key in signal_matrix) or (len(signal_matrix) == 0): 202 | return None 203 | 204 | sell_level = signal_matrix[key]["SELL"] 205 | buy_level = signal_matrix[key]["BUY"] 206 | for epic in signal_matrix.keys(): 207 | sell_level = sell_level and signal_matrix[epic]["SELL"] 208 | buy_level = buy_level and signal_matrix[epic]["BUY"] 209 | 210 | # once you have a signal_matrix made you need to find if a signal exists 211 | signals_levels = { 212 | "SELL": sell_level, 213 | "BUY": buy_level 214 | } 215 | return signals_levels 216 | 217 | def finding_lows_highs(self, data, reset=False): 218 | 219 | bid = data["snapshot"]["bid"] 220 | offer = data["snapshot"]["offer"] 221 | 222 | if reset: 223 | epic = data["instrument"]["epic"] 224 | object_dict = self.map_epic_data_minute[epic][-1] 225 | object_dict["snapshot"]["high"] = self.high 226 | object_dict["snapshot"]["low"] = self.low 227 | self.map_epic_data_minute[epic][-1] = object_dict 228 | # start looking at the new interval 229 | if self.high == None or reset: 230 | self.high = offer 231 | if self.low == None or reset: 232 | self.low = bid 233 | 234 | if bid < self.low: 235 | self.low = bid 236 | if offer > self.high: 237 | self.high = offer 238 | 239 | 240 | 241 | 242 | 243 | 244 | --------------------------------------------------------------------------------