{ "info": { "author": "James K Bowler", "author_email": "james.bowler@datacentauri.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Software Development :: Build Tools" ], "description": "fxcpy\n=====\n\nfxcpy is an open-soured python implementation of the Forexconnect API\nSDK offered by FXCM. The full documentation can be found\n**`here `__**\n\nCurrent Features\n----------------\n\n- **Trading Tables** - fxcpy supports all trading tables in memory for\n fast access updated automatically by the trading server.\n\n - ``AccountsTable`` - contains the data such as account balance,\n used margin, daily PnL, Gross PnL etc...\n - ``OffersTable`` - all instrument attributes, such as symbol, live\n bid/ask pricing, point-size, contract currency etc ...\n - ``OrdersTable`` - holds order attributes until they are executed.\n - ``TradesTable`` - once orders are executed, trades are inserted\n and tracked with various attributes.\n - ``ClosedTradesTable`` - contains trades that are closed for the\n current trading day.\n - ``SummaryTable`` - contains summarised information for every\n instrument with an open position.\n - ``MessagesTable`` - deals with messages sent from the trading\n server, such as a margin call.\n\n- **Trading** - fxcpy is very flexible with many options for executing\n different types of orders.\n\n - OCO (One-Cancels-Other)\n - OTO (One-Triggers-Others)\n - OTOCO (One-Triggers-OCO)\n - Limit, Entry Limit, Trailing Entry Limit\n - Open/Close Market, Market Range\n - Open/Close Limit, Limit Range\n - Stop, Entry Stop, Trailing Stop\n - NET Orders\n - Order cloning\n\n- **Data** - fxcpy supports both live streaming and historical price\n data\n\nRequirements\n------------\n\n- Ubuntu 16.04\n- boost 1.65.1\n- cmake 3.9.6\n- ForexConnectAPI 1.4.1 (included)\n\nInstallation\n------------\n\nA large part of installing this API has to do with Boost & CMAKE,\ntherefore the ``install_script.sh`` includes the installation of both\nand this API. Currently, Ubuntu 16.04 is supported, there are no plans\nto support the Windows operating system. However, support will be added\nfor other Linux variants shortly.\n\nPlease become familiar with the installation process and remove any\nelements already installed on your system. If boost 1.65.1 or higher is\ninstalled using a different path than the usual\n``/usr:/usr/local...etc``, edit the commented values in the\nCMakeLists.txt file located in the ``/cpp`` directory.\n\nFirst download this repository.\n\n.. code:: shell\n\n git clone https://github.com/JamesKBowler/fxcpy.git\n\nSwitch to the ``fxcpy/`` directory.\n\n.. code:: shell\n\n cd fxcpy/\n\nOnce happy with the script execute following.\n\n.. code:: shell\n\n chmod +x install_script.sh && sudo ./install_script.sh\n\nThe script will add an environment variable to /etc/environment file.\nHowever, this will not come into effect until your machine is either\nrebooted or logged out and back in.\n\nTo find out more about environment variables, please read\n**`this `__**\nquestion on askubuntu.\n\n.. code:: shell\n\n export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)/fxcpy/cpp/lib\n\nAfter installation your system will have two modules ``forexconnect``\nand ``fxcpy``. Oh and ``pandas`` if not already installed.\n\nThe ``forexconnect`` module is a C++ Wrapper and ``fxcpy`` is the python\nimplementation. Before using this API in a live trading environment, I\n**highly recommend** testing it first on a demo account, opened for free\nat **`FXCM `__**\n\nHaving FXCM's **`Trading\nStation `__**\nopen at the same to see trades simultaneously executed is a good idea.\n\nBasic Usage\n-----------\n\nWe won't discuss best practices for storing passwords and for\nsimplicity, create a setting.py file to hold your FXCM user, password,\nenvironment and url information.\n\nAn example of such is.\n\n.. code:: python\n\n # /fxcpy/fxcpy/settings.py\n\n USER = \"DEM12345\"\n PASS = \"123456\"\n URL = \"http://www.fxcorporate.com/Hosts.jsp\"\n ENV = \"demo\" # or \"real\"\n\nTo get started create a session by logging into your FXCM account\n\n.. code:: python\n\n from fxcpy.session_handler import SessionHandler\n from fxcpy.settings import USER, PASS, URL, ENV\n\n session_handler = SessionHandler(USER, PASS, URL, ENV, load_tables=True)\n\nMonitoring session status is carried out through the\n``SessionMonitoring`` class, located within the ``SessionHandler``\n\n.. code:: python\n\n status = session_handler.session_monitoring.get_status()\n\nTo obtain information for all offers at FXCM, get the ``OffersTable``\nclass from the ``SessionHandler``\n\n.. code:: python\n\n offers_table = session_handler.get_offers_table()\n\nThe Forexconnect API has no built-in function to find attributes using\nthe instrument symbol, so we must always pass the unique ``offer_id``.\nSure, one could build such a feature. However, this would involve\nlooping over each row in the table on every call.\n\nAll offer attributes are accessed through the ``OffersTable`` like this.\n\n.. code:: python\n\n offer = offers_table.get_offer_ids()\n\n offer = {\n 'AUD/CAD': '16',\n 'AUD/CHF': '39',\n 'AUD/JPY': '17',\n 'AUD/NZD': '28',\n 'AUD/USD': '6',\n 'AUS200': '1001',\n 'Bund': '3001',\n 'CAD/CHF': '90',\n 'CAD/JPY': '18',\n 'CHF/JPY': '12',\n 'CHN50': '1020',\n 'Copper': '1016',\n 'ESP35': '1002',\n 'EUR/AUD': '14',\n 'EUR/USD': '1',\n .....\n }\n\n offers_table.get_contract_currency(offer['EUR/USD'])\n\nAll other tables are accessed the same way.\n\n.. code:: python\n\n orders_table.get_whatever(order_id)\n trades_table.get_whatever(trade_id)\n\nand so on ..\n\nExecuting a trade is super easy using the\\ ``TradingCommands`` class.\n\n.. code:: python\n\n trading_commands = session_handler.get_trading_commands()\n\nNext, execute 5 SHORT trades for the EUR/USD, with stop loss and limit\norders with one API call.\n\nThis example will place a stop loss 15 pips above and a limit order 30\npips below the current price.\n\n.. code:: python\n\n # Instrument\n offer_id = offer['EUR/USD']\n # Point Size\n psize = offers_table.get_point_size(offer_id) # 0.0001\n # 15 pip Stop Loss Order\n stop = offers_table.get_bid(offer_id) + 15.0 * psize\n # 30 pip Limit Order\n limit = offers_table.get_bid(offer_id) - 30.0 * psize\n # Order amount\n amount = 1 # 1k lot\n # BuySell direction\n buysell = \"S\" # Short\n\n # Master valuemap container\n master = trading_commands.create_valuemap()\n for i in range(5):\n # Create the order\n child = trading_commands.create_open_market_order(\n offer_id,\n buysell,\n amount\n )\n # Attach Market order to the master_valuemap\n master.appendChild(child)\n # Attach Limit & Stop Order to the child valuemap\n master = trading_commands.attach_stoplimit_orders(\n i, # valuemap index\n master,\n rate_stop=stop, \n rate_limit=limit\n )\n # Execute with one API call\n trading_commands.execute_order(master)\n # Lock the GIL (global interpreter lock) until trade is executed.\n response_listener.wait_events()\n\nCheck out the ``/tests`` directory for more examples.\n\nMonitoring of trade execution is carried out using the ``OrderMoitor``\nclass, which is updated by the ``TableListener``.\n\n.. code:: python\n\n order_monitor = session_handler.get_order_monitor()\n\n orders = order_monitor.get_monitors()\n\nEach ``trade_id`` has its own monitoring class, with each subsequent\norder appended to the initial trade conveniently wrapped in a\ndictionary.\n\n.. code:: python\n\n monitors = order_monitor.get_monitors()\n\n {'91133665': ,\n '91133774': ,\n '91145522': ,\n '91145541': ,\n ...\n ...}\n\n # Access using trade_id\n order = monitors['91133665']\n\n order.get_result()\n\n \"Executed\"\n\n order.get_state()\n\n \"OrderExecuted\"\n\nTo close all positions at the current market price, extract trade\nattributes from the ``TradesTable`` class.\n\n.. code:: python\n\n master_valuemap = trading_commands.create_valuemap()\n for trade_id, offer_id in trades_table.get_trade_ids().items():\n direction = trades_table.get_buysell(trade_id)\n if direction == 'B':\n buysell = 'S'\n else: # direction == 'S'\n buysell = 'B'\n amount = trades_table.get_amount(trade_id)\n child_valuemap = trading_commands.create_close_market_order(\n offer_id,\n buysell,\n trade_id=trade_id,\n amount=amount,\n net_quantity='N'\n )\n master_valuemap.appendChild(child_valuemap)\n trading_commands.execute_order(master_valuemap)\n response_listener.wait_events()\n\nPrice History\n~~~~~~~~~~~~~\n\nFXCM has tons of free data, and the ``MarketData`` class will provide\naccess to these data.\n\nNote:\n\n- FXCM servers will never return more than 300 bars of data in one API\n call.\n- All datetime is stored in UTC and of type OLE automation, for\n instance ``float(0.0) = datetime(1899,12,30)``, take a look in the\n ``/utils`` directory.\n\n.. code:: python\n\n from datetime import datetime\n from fxcpy.utils.date_utils import to_ole\n\n market_data = session_handler.get_market_data()\n\n data_gen = market_data.get_price_data(\"GBP/USD\", \"D1\", 0.0, to_ole(datetime.utcnow()))\n\n data = next(data_gen)\n print(data)\n\nGenerator returns a structured numpy array.\n\n.. code:: python\n\n np.array([\n ('2018-02-22T22:00:00', 1.39587, 1.40062, 1.39044, 1.3977 , 1.39506, 1.4005 , 1.39043, 1.39689, 315585),\n ('2018-02-25T22:00:00', 1.3991 , 1.40706, 1.39288, 1.39702, 1.3985 , 1.40695, 1.39275, 1.39651, 306833),\n ('2018-02-26T22:00:00', 1.39702, 1.39974, 1.38583, 1.39124, 1.39651, 1.39958, 1.3857 , 1.3904 , 393485),\n ('2018-02-27T22:00:00', 1.39124, 1.39169, 1.37571, 1.37629, 1.3904 , 1.39157, 1.37562, 1.3759 , 377407),\n ('2018-02-28T22:00:00', 1.37629, 1.37863, 1.37123, 1.37783, 1.3759 , 1.37848, 1.37111, 1.37745, 300786),\n ('2018-03-01T22:00:00', 1.37783, 1.38177, 1.37562, 1.38046, 1.37745, 1.38162, 1.37548, 1.37992, 289091),\n ('2018-03-04T22:00:00', 1.38026, 1.38783, 1.37674, 1.38503, 1.37984, 1.38769, 1.37658, 1.38478, 319845),\n ('2018-03-05T22:00:00', 1.38503, 1.39304, 1.38175, 1.3889 , 1.38478, 1.39289, 1.3816 , 1.38848, 305963),\n ('2018-03-06T22:00:00', 1.3889 , 1.39135, 1.38469, 1.3902 , 1.38848, 1.39121, 1.38453, 1.38943, 326001),\n ('2018-03-07T22:00:00', 1.3902 , 1.39111, 1.37824, 1.38121, 1.38943, 1.39093, 1.37803, 1.38061, 672878),\n ('2018-03-08T22:00:00', 1.38121, 1.389 , 1.3789 , 1.38549, 1.38061, 1.38886, 1.37875, 1.38486, 309030)],\n dtype=[('date', '