pareeohnos / ktrade Goto Github PK
View Code? Open in Web Editor NEWA simple UI for managing your trades
License: MIT License
A simple UI for managing your trades
License: MIT License
The app will be installed through pip
and should expose a ktrade
command to launch the app. Setup should be as simple as
pip install ktrade
ktrade
daven
reported a failure trying to start up on python 3.9
:\ktrade-main>flask db upgrade
Traceback (most recent call last):
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 86, in _run_code
exec(code, run_globals)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\Scripts\flask.exe\__main__.py", line 7, in <module>
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\cli.py", line 990, in main
cli.main(args=sys.argv[1:])
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\cli.py", line 596, in main
return super().main(*args, **kwargs)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\click\core.py", line 1053, in main
rv = self.invoke(ctx)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\click\core.py", line 1659, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\click\core.py", line 1659, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\click\core.py", line 1395, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\click\core.py", line 754, in invoke
return __callback(*args, **kwargs)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\click\decorators.py", line 26, in new_func
return f(get_current_context(), *args, **kwargs)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\cli.py", line 439, in decorator
with __ctx.ensure_object(ScriptInfo).load_app().app_context():
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\cli.py", line 406, in load_app
app = locate_app(self, import_name, None, raise_if_not_found=False)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\cli.py", line 256, in locate_app
__import__(module_name)
File "C:\ktrade-main\wsgi.py", line 4, in <module>
from application import create_app, db, socketio
File "C:\ktrade-main\application.py", line 9, in <module>
from flask_socketio import SocketIO
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\flask_socketio\__init__.py", line 9, in <module>
from socketio import socketio_manage # noqa: F401
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\socketio\__init__.py", line 9, in <module>
from .zmq_manager import ZmqManager
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\socketio\zmq_manager.py", line 5, in <module>
import eventlet.green.zmq as zmq
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\eventlet\__init__.py", line 17, in <module>
from eventlet import convenience
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\eventlet\convenience.py", line 7, in <module>
from eventlet.green import socket
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\eventlet\green\socket.py", line 4, in <module>
__import__('eventlet.green._socket_nodns')
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\eventlet\green\_socket_nodns.py", line 11, in <module>
from eventlet import greenio
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\eventlet\greenio\__init__.py", line 3, in <module>
from eventlet.greenio.base import * # noqa
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\eventlet\greenio\base.py", line 32, in <module>
socket_timeout = eventlet.timeout.wrap_is_timeout(socket.timeout)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\eventlet\timeout.py", line 166, in wrap_is_timeout
base.is_timeout = property(lambda _: True)
TypeError: cannot set 'is_timeout' attribute of immutable type 'TimeoutError'
C:\ktrade-main>
C:\ktrade-main>python -V
Python 3.10.0
If the connection to TWS fails, the app should handle this in a nice way. Ideally it should present something to users on the UI so they are aware that things aren't working correctly.
This includes on launch of the app. If it can't connect when it first starts it already keeps trying until it can, however this is not reflected in the UI
When the app launches and connects to TWS, it should subscribe to updates for all watched tickers, and pull their historical data to calculate the ADR
Right now the app fetches the account size on load, however some people trade using large accounts but only want to trade with a set amount of that. The app should allow you to configure your trading capital, and use that for calculations instead of getting the account size from TWS
The UI needs a way of presenting notifications - success, warnings, errors
I should be able to trim an existing position by 1/2 or 1/3 with a button click. This should handle the selling of that amount, and if needed adjusting the stop loss to the break even point
In order to correctly calculate position sizes when buying, we need to know details about the users account - specifically how large it is. The max size and risk of a trade is a percentage of your entire account, so without knowing what that is it cannot calculate the position size. Some code to pull this in thanks to Dolivent
class IB(EWrapper, EClient):
def __init__(self):
EWrapper.__init__(self)
EClient.__init__(self, wrapper=self)
self.connected = threading.Event()
self.connect("127.0.0.1", 7496, 1) # TODO pull address and port from config
self.liquidityEstablished = threading.Event()
self.liquidity = None
def __del__(self):
self.disconnect()
# called when connection is actually established with TWS
def nextValidId(self, orderId:int):
self.connected.set()
def getLiquidity(self):
self.connected.wait()
self.reqAccountSummary(9002, "All", "$LEDGER:USD")
self.liquidityEstablished.wait()
return self.liquidity
def accountSummary(self, reqId:int, account:str, tag:str, value:str,
currency:str):
if tag == "NetLiquidationByCurrency":
self.liquidity = float(value)
self.liquidityEstablished.set()
Notifications in the app are a little messy at the moment. If for instance you place a huge order that is filled in multiple parts, you will get one notification for each part in quick succession.
Instead, the app should attempt to replace existing notifications an be clever. For example, if you place a huge order you should get one to say something like "Order filling", then it would update to say "Order filling: 1000/3000", then eventually update to success saying it's filled.
When the app tries to buy a stock, it will calculate the position size based on your risk factors. In the event that the resulting position size calculated exceeds your buying power, the app needs to know what to do. The options are either:
Need to be careful with the latter option, as it won't be able to simply buy the full amount in the account, otherwise the order will be rejected due to no money to pay for the fees
There should be a Orders
/Trades
tab which shows all current open orders, as well as all old orders. This should contain details such as entry price, a history of actions taken against it (such as trim points, stop loss triggers etc)
When the stop loss orders are added, they're are only good for the DAY, not GTC which they should be
The UI is currently thrown together quickly. it should have a real design
When a new ticker is added to the watch list, the app needs to retrieve the historical data for the last 20 days to calculate the ADR
When I close a position, the trade disappears and then the app crashes
The trade should be closed, but shouldn't be deleted. The app should not crash
Relevant log section
INFO:werkzeug:127.0.0.1 - - [28/Sep/2021 00:06:44] "POST /trades/1/close HTTP/1.1" 200 -
INFO:ibapi.client:SENDING placeOrder b'\x00\x00\x01:3\x00555\x000\x00AAPL\x00STK\x00\x000.0\x00\x00\x00SMART\x00\x00USD\x00\x00\x00\x00\x00SELL\x0075.0\x00MKT\x00\x00\x00\x00\x00\x00\x000\x00\x001\x000\x000\x000\x000\x000\x000\x000\x00\x000\x00\x00\x00\x00\x00\x00\x00\x000\x00\x00-1\x000\x00\x00\x000\x00\x00\x001\x001\x00\x000\x00\x00\x00\x00\x00\x000\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000\x00\x00\x000\x000\x00\x00\x000\x00\x000\x000\x000\x000\x00\x001.7976931348623157e+308\x001.7976931348623157e+308\x001.7976931348623157e+308\x001.7976931348623157e+308\x001.7976931348623157e+308\x000\x00\x00\x00\x001.7976931348623157e+308\x00\x00\x00\x00\x000\x000\x000\x00\x00'
INFO:ibapi.client:REQUEST cancelOrder {'orderId': 554}
INFO:ibapi.client:SENDING cancelOrder b'\x00\x00\x00\x084\x001\x00554\x00'
INFO:ibapi.wrapper:ANSWER error {'reqId': 555, 'errorCode': 2168, 'errorString': "Warning: The 'EtradeOnly' order attribute is not supported."}
ERROR:ibapi.wrapper:ERROR 555 2168 Warning: The 'EtradeOnly' order attribute is not supported.
INFO:ibapi.wrapper:ANSWER error {'reqId': 555, 'errorCode': 2169, 'errorString': "Warning: The 'FirmQuoteOnly' order attribute is not supported."}
ERROR:ibapi.wrapper:ERROR 555 2169 Warning: The 'FirmQuoteOnly' order attribute is not supported.
INFO:werkzeug:127.0.0.1 - - [28/Sep/2021 00:06:44] "OPTIONS /trades/1 HTTP/1.1" 200 -
INFO:werkzeug:127.0.0.1 - - [28/Sep/2021 00:06:44] "DELETE /trades/1 HTTP/1.1" 200 -
INFO:ibapi.wrapper:ANSWER tickString {'reqId': 552, 'tickType': 48, 'value': '144.47;25.0000000000000000;1632751604613;177457.0000000000000000;144.5486743;false'}
INFO:ibapi.wrapper:ANSWER tickString {'reqId': 552, 'tickType': 84, 'value': 'D'}
INFO:ibapi.wrapper:ANSWER tickPrice {'reqId': 552, 'tickType': 4, 'price': 144.48, 'attrib': 2912071928656: CanAutoExecute: 0, PastLimit: 0, PreOpen: 0}
INFO:werkzeug:127.0.0.1 - - [28/Sep/2021 00:06:44] "GET /socket.io/?EIO=4&transport=polling&t=Nmdb5A8&sid=JeWpuWKA8soLl8dyAAAA HTTP/1.1" 200 -
INFO:ibapi.wrapper:ANSWER tickSize {'reqId': 552, 'tickType': 5, 'size': 20}
INFO:ibapi.wrapper:ANSWER tickSize {'reqId': 552, 'tickType': 5, 'size': 20}
INFO:ibapi.wrapper:ANSWER tickSize {'reqId': 552, 'tickType': 8, 'size': 176955}
INFO:ibapi.wrapper:ANSWER orderStatus {'orderId': 554, 'status': 'Cancelled', 'filled': 0.0, 'remaining': 75.0, 'avgFillPrice': 0.0, 'permId': 718392687, 'parentId': 553, 'lastFillPrice': 0.0, 'clientId': 1, 'whyHeld': '', 'mktCapPrice': 0.0}
INFO:ibapi.wrapper:ANSWER error {'reqId': 554, 'errorCode': 202, 'errorString': 'Order Canceled - reason:'}
ERROR:ibapi.wrapper:ERROR 554 202 Order Canceled - reason:
INFO:ibapi.client:disconnecting
INFO:ibapi.wrapper:ANSWER connectionClosed {}
Exception in thread Thread-12:
Traceback (most recent call last):
File "C:\Users\pc_mo\AppData\Local\Programs\Python\Python39\lib\threading.py", line 973, in _bootstrap_inner
self.run()
File "C:\Users\pc_mo\AppData\Local\Programs\Python\Python39\lib\threading.py", line 910, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\pc_mo\PycharmProjects\ktrade\ktrade\providers\ib_provider.py", line 205, in ib_loop
self.api.run()
File "C:\Users\pc_mo\AppData\Local\Programs\Python\Python39\lib\site-packages\ibapi\client.py", line 263, in run
self.decoder.interpret(fields)
File "C:\Users\pc_mo\AppData\Local\Programs\Python\Python39\lib\site-packages\ibapi\decoder.py", line 1294, in interpret
self.interpretWithSignature(fields, handleInfo)
File "C:\Users\pc_mo\AppData\Local\Programs\Python\Python39\lib\site-packages\ibapi\decoder.py", line 1275, in interpretWithSignature
method(*args)
File "C:\Users\pc_mo\PycharmProjects\ktrade\ktrade\providers\ib\api.py", line 277, in error
trade_failed(trade, errorString)
File "C:\Users\pc_mo\PycharmProjects\ktrade\ktrade\provider_actions.py", line 40, in trade_failed
trade = Trade.find(session, trade.id)
File "C:\Users\pc_mo\PycharmProjects\ktrade\ktrade\models.py", line 13, in find
return session.query(cls).filter_by(id=id).one()
File "C:\Users\pc_mo\AppData\Local\Programs\Python\Python39\lib\site-packages\sqlalchemy\orm\query.py", line 2730, in one
return self._iter().one()
File "C:\Users\pc_mo\AppData\Local\Programs\Python\Python39\lib\site-packages\sqlalchemy\engine\result.py", line 1373, in one
return self._only_one_row(True, True, False)
File "C:\Users\pc_mo\AppData\Local\Programs\Python\Python39\lib\site-packages\sqlalchemy\engine\result.py", line 562, in _only_one_row
raise exc.NoResultFound(
sqlalchemy.exc.NoResultFound: No row was found when one was required
Currently, the main Trade
model has a stop_order_id
column for tracking the stop loss order, however TWS reports statuses on the stop loss order separately. We should keep a track of this order separately so we can more accurately report the status of things.
We should either create a separate model for it, or (probably better) has child records (i.e add a parent_id column)
As requested by Corringham
I'd like the ability to load up some select EP Tickers chosen in the premarket, which then executes automatically during the open using straight KK defined opening range breakout criteria (with dynamic position sizing, SL placement, and ADR vs Range validation). I note your excellent tool looks to do the live pricing and position sizing with equity risk, but pushing the button on execution I think is manual? Would be great to set the Tickers, and it will trade them off a 1min ORH, and if stopped out will automatically reset (live checking ADR vs Range) and trade on a 5min ORH breakout, and then reset and go in on a 1 hour break. I'm basically doing this mechanically during the day using a spreadsheet, but being at the screen and executing isn't really adding any value to the process. To me the value is in choosing the right stocks to trade as EPs. I'd also like to spend more time Australia, so I'm happy choosing the stocks, putting execution on auto pilot would mean getting some sleep! Thanks in advance for any wisdom or pointers you might have!
When we trim, the status of the trade switches to 'canceled' when it shouldn't. Ideally we should introduce one or more new statuses to cover these situations. Need to decide whether a trimmed order should still be shown as "complete" or do we mark it as "trimmed", or even "trimmed "
@Dolivent thoughts?
It should be possible to delete trades within KTrade. This might be because you don't want to manage it through KTrade, or you just want to clean up some clutter
When a new ticker is added to the watch list, it should register for real-time events from TWS. This is required so KTrade can calculate things like ADR, LOD etc and keep monitoring that ticker for updates
There is still a bug with the LOD calculations that is messing up entries, and it is extremely obvious when trying to enter an EP setup. It seems the app is loading yesterdays LOD values. One possibility is that TWS is not reporting the latest values when fetching historical data, so we need to change the time unit from days
to something smaller. As small as possible would be best
Maybe a common user error. Prompt if the user tries to duplicate order?
The BUY
button currently does nothing. This should be hooked up so that it buys that stock with the appropriate values
When the app first starts up, it pulls in the last 20 days of bars and grabs the last one to get the LOD. TWS is reporting up to the time it was requested however, so this means the LOD is incorrect.
The app needs a better way of determining the LOD when it starts up, and also a way of refreshing this if the app is started before market opens.
If I place an order using KTrade, shut the app, then open it again some other time such as mid-way through a trading day, it's possible that orders I placed have been stopped out or something else has changed.
When the app loads, it should fetch the latest status of each trade it has made, and update them accordingly
When adding a ticker to your list of watched tickers, it is currently added immediately. Instead, it should be validated to ensure it is a real ticker, and on an exchange that KTrade (IB) supports.
When you add a new ticker to your watch list, it raises an exception and requires a page refresh before the details are updated correctly
Trim buttons should be able to sell no more than the shares you own. Even if you submit a trim order, it hasn't been filled, and you click the button again (for whatever reason). A scenario where this is critical is if someone accidentally double clicks and submits sell orders in total in excess of what they have available to sell
When trimming/closing a position, the table does not get updated after the order goes through. It should automatically refresh the moment there is an update from the server
When typing a ticker into the "Add ticker" input, it should present a list of possible results
Edit: original problem was that the stop didn't adjust quantities. This works and was probably a user error.
New problem is that when you trim to close the position, the stop loss doesn't match the shares remaining. The program should check the stop loss quantity against the positions quantity
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.