Closed tomer-ds closed 7 months ago
Hi,
I'm glad to help. But i would need more information. based the error message that you reported it seems like an error with port 4000.
I'm not sure why you are sharing IBC's config file. it's not needed as it's by default part of the container.
By default IBC will change IB gateways port to 4000. but on the file that you shared it's not using port 4000 --> OverrideTwsApiPort=
. So i don't know why you are sharing it, or what is your expectation on the file that you are sharing. But something is telling me that might be cause of the problem.
So as i said I'm happy to help. but i would need more details on what you are doing.
if you copy the docker-compose.yml file and create an .env
file with the content shown on the README.md you get a working container. as simple as that. that's actually my objective that this just works.
1) are you pulling the image from ghcr.io?
2) are you building it locally? in this case many things can go wrong
3) if (1) can you share the output of docker compose config
. please exclude your user&pass
4) can you share the output of docker compose up
Ok so I think I understood my disconnect. I was attempting to use my own configuration file without prompting the image with the env "CUSTOM_CONFIG" I guess I need also need to work on that configuration. Since I am running this in Kubernetes, my configMap will overwrite whatever file you have put in the image, but I guess this is what was breaking, because I configured the deployment with a selection of the EnvVars you require (analogous to .env file) and now the error has stopped
env:
- name: TWS_USERID
value: {{ .Values.ibcConfig.twsUserId }}
- name: TWS_PASSWORD
value: {{ .Values.ibcConfig.twsPassword }}
- name: TRADING_MODE
value: {{ .Values.ibcConfig.tradingMode }}
- name: READ_ONLY_API
value: "no"
- name: VNC_SERVER_PASSWORD
value: {{ .Values.ibcConfig.vncServerPassword }}
- name: TWOFA_TIMEOUT_ACTION
value: restart
- name: AUTO_RESTART_TIME
value: 8:00AM
- name: RELOGIN_AFTER_2FA_TIMEOUT
value: "yes"
Anyway, huge thanks again for the great image. If you would like to have a look at my helm chart just let me know, might be a nice addition to your project It would require some cooperation between us to ensure everything is exposed as per your requirements, but totally doable
Apologies for closing and reopening... I litterally just checked back and I have started seeing new error
socat[272] E connect(5, AF=2 127.0.0.1:4000, 16): Connection timed out
Can you tell me how this port is connected? Does socat request somehow require 4000 to open on the container? Maybe I need to open it on the kubernetes pod?
I realize I never answered all your questions:
---
# Source: ib-gateway/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ib-gateway
labels:
helm.sh/chart: ib-gateway-0.1.0
app.kubernetes.io/name: ib-gateway
app.kubernetes.io/instance: ib-gateway
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ib-gateway
app.kubernetes.io/instance: ib-gateway
template:
metadata:
labels:
app.kubernetes.io/name: ib-gateway
app.kubernetes.io/instance: ib-gateway
spec:
serviceAccountName: ib-gateway
securityContext:
{}
containers:
- name: ib-gateway
securityContext:
{}
env:
- name: TWS_USERID
value: *******
- name: TWS_PASSWORD
value: *******
- name: TRADING_MODE
value: paper
- name: READ_ONLY_API
value: "no"
- name: VNC_SERVER_PASSWORD
value: ********
- name: TWOFA_TIMEOUT_ACTION
value: restart
- name: AUTO_RESTART_TIME
value: 8:00AM
- name: RELOGIN_AFTER_2FA_TIMEOUT
value: "yes"
image: "ghcr.io/gnzsnz/ib-gateway:stable"
imagePullPolicy: IfNotPresent
resources:
{}
ports:
- name: ibgatewaylive
containerPort: 4001
protocol: TCP
- name: ibgatewaypaper
containerPort: 4002
protocol: TCP
- name: vnc
containerPort: 5900
protocol: TCP
4. can you share the output of docker compose up - How necessary is this? If crucial I will do so. I was hoping to avoid this process, so all I've been working with is your image from GHCR and not the repo itself
Some context to the error
2023-10-30 09:57:52:945 IBC: detected frame entitled: Starting application...; event=Closed
2023-10-30 09:57:52:946 IBC: Login has completed
2023-10-30 09:57:52:948 IBC: detected dialog entitled: DU8017938 Trader Workstation Configuration (Simulated Trading); event=Focused
2023-10-30 09:57:53:016 IBC: Performing port configuration
Forking :::4000 onto 0.0.0.0:4002
2023/10/30 08:04:33 socat[244] E connect(5, AF=2 127.0.0.1:4000, 16): Connection timed out
2023/10/30 08:04:37 socat[245] E connect(5, AF=2 127.0.0.1:4000, 16): Connection timed out
2023/10/30 08:04:39 socat[246] E connect(5, AF=2 127.0.0.1:4000, 16): Connection timed out
Would yo prefer the entire log?
hi,
you need to look the scripts used by the container.
run.sh
script drives everything. your problem is related to fork_ports_delayed.sh.
if you don't use CUSTOM_CONFIG
then the IBC config.ini file in the container will change IB gateways port from 4000 to 4001/4002, and socat will be free to use port 4000. this is something that i plan to change at some point because is confusing. but is how the original dev set it.
if you ARE using CUSTOM_CONFIG
then you need to handle the port yourself. and this is what (I think) you are not doing. check what the container does, understand it and then put your changes on top. I won't work otherwise.
How can I contribute? Would you prefer me to create a branch with a PR or maybe a fork?
@tomer-ds there is nothing to commit into the repo. you just need to adjust your settings accordingly.
So I tried both scenarios and even if I do not give custom config, i still get the error
I was thinking maybe it was an issue with Socat running in Kubernetes POD... So I found a way to get Socat as sidecar container, but in order to support this I need to edit run.sh and add the option to NOT run socat via the container itself
I'm afraid that I won't be able to help you.
the container works well, it's an issue your setup. a fresh container pulled from ghcr.io using the docker-compose.yml and .env file in the README.md file works just fine.
I can't help you with helm/kubernetes.
make sure that when you start the container you can see
ib-gateway-docker-ib-gateway-1 | 2023-11-01 12:26:01:908 IBC: Performing port configuration
ib-gateway-docker-ib-gateway-1 | 2023-11-01 12:26:01:908 IBC: TWS API socket port was set to 4002
ib-gateway-docker-ib-gateway-1 | 2023-11-01 12:26:01:909 IBC: TWS API socket port now set to 4000
and a few lines bellow
ib-gateway-docker-ib-gateway-1 | Forking :::4000 onto 0.0.0.0:4002
This will change default port from 4001/4002 to 4000 (the container does it so you don't have to do it) and then socat will pipe anything connecting in 0.0.0.0:4001/4002 to localhost:4000. if you overwrite what the container does then you need to manage it by yourself.
Quite right, indeed docker compse works just fine. I guess it has something to do with what is going in the kubernetes pod. Anyway I guess I will go and find that out.
Thanks anyway for the great container! I will create a fork and see what magic I can do 🙏🏼
@gnzsnz thank you for putting this image together. Looking for a little guidance on using it - I think I'm close but might be doing something obviously wrong. Maybe this will help someone in the future as well.
I'm creating an image with this Dockerfile
FROM ghcr.io/gnzsnz/tws-rdesktop:10.26
# Prepare system
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends --yes \
telnet \
vim \
python3-pip \
python3-setuptools \
&& if test "$(dpkg --print-architecture)" = "armhf" ; then python3 -m pip config set global.extra-index-url https://www.piwheels.org/simple ; fi \
&& pip install pipenv \
&& pip uninstall -y setuptools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
WORKDIR /home/ibgateway/
COPY Pipfile .
COPY Pipfile.lock .
COPY code ./code
COPY config/ibc/config.ini.tmpl /opt/ibc/config.ini.tmpl
# Install dependencies
RUN sudo pipenv install --system --deploy
This builds and starts successfully with the following docker-compose.yml
file:
version: "3.4"
name: algo-trader
services:
tws:
restart: always
shm_size: "2gb" #optional
security_opt:
- seccomp:unconfined #optional
build:
context: .
dockerfile: Dockerfile
tags:
- "ib-gateway:latest"
image: ib-gateway:latest
platform: linux/amd64
environment:
PUID: 1000
PGID: 1000
PASSWD: ${PASSWD:-}
TWS_USERID: ${TWS_USERID}
TWS_PASSWORD: ${TWS_PASSWORD}
TRADING_MODE: ${TRADING_MODE:-paper}
TWS_SETTINGS_PATH: ${TWS_SETTINGS_PATH:-}
READ_ONLY_API: ${READ_ONLY_API:-}
TWOFA_TIMEOUT_ACTION: ${TWOFA_TIMEOUT_ACTION:-exit}
BYPASS_WARNING: ${BYPASS_WARNING:-}
AUTO_RESTART_TIME: ${AUTO_RESTART_TIME:-}
AUTO_LOGOFF_TIME: ${AUTO_LOGOFF_TIME:-}
SAVE_TWS_SETTINGS: ${SAVE_TWS_SETTINGS:-}
RELOGIN_AFTER_TWOFA_TIMEOUT: ${RELOGIN_AFTER_TWOFA_TIMEOUT:-no}
TWOFA_EXIT_INTERVAL: ${TWOFA_EXIT_INTERVAL:-60}
TIME_ZONE: ${TIME_ZONE:-Etc/UTC}
TZ: ${TIME_ZONE:-Etc/UTC}
CUSTOM_CONFIG: ${CUSTOM_CONFIG:-NO}
SSH_TUNNEL: ${SSH_TUNNEL:-}
SSH_OPTIONS: ${SSH_OPTIONS:-}
SSH_ALIVE_INTERVAL: ${SSH_ALIVE_INTERVAL:-}
SSH_ALIVE_COUNT: ${SSH_ALIVE_COUNT:-}
SSH_PASSPHRASE: ${SSH_PASSPHRASE:-}
SSH_REMOTE_PORT: ${SSH_REMOTE_PORT:-}
SSH_USER_TUNNEL: ${SSH_USER_TUNNEL:-}
SSH_RESTART: ${SSH_RESTART:-}
SSH_RDP_PORT: ${SSH_RDP_PORT:-}
ports:
- "127.0.0.1:7496:7498" # live
- "127.0.0.1:7497:7499" # paper
- "127.0.0.1:3370:3389" # xrdp
And this .env
file
TWS_USERID=my-user-id
TWS_PASSWORD=my-pass
TWS_SETTINGS_PATH=
TRADING_MODE=paper
READ_ONLY_API=no
VNC_SERVER_PASSWORD=myVncPassword
TWOFA_TIMEOUT_ACTION=restart
BYPASS_WARNING=
AUTO_RESTART_TIME=11:59 PM
AUTO_LOGOFF_TIME=
SAVE_TWS_SETTINGS=
RELOGIN_AFTER_2FA_TIMEOUT=yes
TIME_ZONE=Etc/UTC
CUSTOM_CONFIG=
SSH_TUNNEL=
SSH_OPTIONS=
SSH_ALIVE_INTERVAL=
SSH_ALIVE_COUNT=
SSH_PASSPHRASE=
SSH_REMOTE_PORT=
SSH_USER_TUNNEL=
SSH_RESTART=
SSH_VNC_PORT=
The one change to config.ini.tmpl
I made was to set AcceptIncomingConnectionAction=accept
The container starts successfully and I can see that port 7499
is open but every connection request is being refused:
algo-trader-tws-1 | Forking :::7497 onto 0.0.0.0:7499 > trading mode paper
algo-trader-tws-1 | 2023/11/30 21:26:41 socat[1494] E connect(5, AF=2 127.0.0.1:7497, 16): Connection refused
algo-trader-tws-1 | 2023/11/30 21:28:47 socat[1699] E connect(5, AF=2 127.0.0.1:7497, 16): Connection refused
algo-trader-tws-1 | 2023/11/30 21:33:34 socat[2196] E connect(5, AF=2 127.0.0.1:7497, 16): Connection refused
algo-trader-tws-1 | 2023/11/30 21:36:38 socat[2494] E connect(5, AF=2 127.0.0.1:7497, 16): Connection refused
algo-trader-tws-1 | 2023/11/30 21:39:15 socat[2750] E connect(5, AF=2 127.0.0.1:7497, 16): Connection refused
algo-trader-tws-1 | 2023/11/30 21:40:57 socat[2926] E connect(5, AF=2 127.0.0.1:7497, 16): Connection refused
I'm exec'ing into the container and trying to connect via telnet and through a python script using ib_insync
. This is the script
import asyncio
import logging
import time
from ib_insync import IB, util
util.patchAsyncio()
def onConnected():
logging.info("CONNECTED TO IB")
time.sleep(10)
ib = IB()
ib.connectedEvent += onConnected
completion_future = asyncio.Future()
ib.connect(
"127.0.0.1",
7499,
clientId=1,
timeout=4,
account="my-account-number",
)
If I'm following along correctly I should be able to connect to 7499
through my script because the container is exposing that port locally. Or do I need to go the ssh bastion route?
Appreciate any tips you might have
Alright, I got something basic working. I am just going to drop this here in case anyone comes across it later:
Dockerfile:
# Use latest stable version
FROM ghcr.io/gnzsnz/ib-gateway:10.19
# Prepare system
USER root
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends --yes \
python3-pip \
python3-setuptools \
&& if test "$(dpkg --print-architecture)" = "armhf" ; then python3 -m pip config set global.extra-index-url https://www.piwheels.org/simple ; fi \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& pip install pipenv
# Copy app files
COPY Pipfile /home/ibgateway
COPY Pipfile.lock /home/ibgateway
COPY code /home/ibgateway/code
# Install dependencies
RUN pipenv install --system --deploy
RUN chown -R ibgateway:ibgateway /home/ibgateway/code
USER ibgateway
WORKDIR /home/ibgateway
Docker Compose file:
version: "3.4"
name: ib-gateway
services:
ib-gateway:
restart: always
build:
context: .
dockerfile: Dockerfile
tags:
- "ib-gateway:latest"
image: ib-gateway:latest
platform: linux/amd64
environment:
TWS_USERID: ${TWS_USERID}
TWS_PASSWORD: ${TWS_PASSWORD}
TRADING_MODE: ${TRADING_MODE:-paper}
TWS_SETTINGS_PATH: ${TWS_SETTINGS_PATH:-}
READ_ONLY_API: ${READ_ONLY_API:-}
VNC_SERVER_PASSWORD: ${VNC_SERVER_PASSWORD:-}
TWOFA_TIMEOUT_ACTION: ${TWOFA_TIMEOUT_ACTION:-exit}
BYPASS_WARNING: ${BYPASS_WARNING:-}
AUTO_RESTART_TIME: ${AUTO_RESTART_TIME:-}
AUTO_LOGOFF_TIME: ${AUTO_LOGOFF_TIME:-}
SAVE_TWS_SETTINGS: ${SAVE_TWS_SETTINGS:-}
RELOGIN_AFTER_TWOFA_TIMEOUT: ${RELOGIN_AFTER_TWOFA_TIMEOUT:-no}
TWOFA_EXIT_INTERVAL: ${TWOFA_EXIT_INTERVAL:-60}
TIME_ZONE: ${TIME_ZONE:-Etc/UTC}
TZ: ${TIME_ZONE:-Etc/UTC}
CUSTOM_CONFIG: ${CUSTOM_CONFIG:-NO}
SSH_TUNNEL: ${SSH_TUNNEL:-}
SSH_OPTIONS: ${SSH_OPTIONS:-}
SSH_ALIVE_INTERVAL: ${SSH_ALIVE_INTERVAL:-}
SSH_ALIVE_COUNT: ${SSH_ALIVE_COUNT:-}
SSH_PASSPHRASE: ${SSH_PASSPHRASE:-}
SSH_REMOTE_PORT: ${SSH_REMOTE_PORT:-}
SSH_USER_TUNNEL: ${SSH_USER_TUNNEL:-}
SSH_RESTART: ${SSH_RESTART:-}
SSH_VNC_PORT: ${SSH_VNC_PORT:-}
ports:
- "127.0.0.1:4001:4003"
- "127.0.0.1:4002:4004"
- "127.0.0.1:5900:5900"
Pipfile:
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
ib-insync = "*"
asyncio = "*"
pandas = "*"
[dev-packages]
black = "*"
[requires]
python_version = "3.10"
python_full_version = "3.10.12"
Python script:
"""
main.py
"""
from ib_insync import * # pylint: disable=wildcard-import,unused-wildcard-import
ib = IB()
ib.connect("127.0.0.1", 4004, clientId=1)
contract = Forex("EURUSD")
bars = ib.reqHistoricalData(
contract,
endDateTime="",
durationStr="30 D",
barSizeSetting="1 hour",
whatToShow="MIDPOINT",
useRTH=True,
)
df = util.df(bars)
print(df)
Don't forget to add a .env
file before running docker compose up --build
TWS_USERID=your-user-id
TWS_PASSWORD=your-pass
TWS_SETTINGS_PATH=
TRADING_MODE=paper
READ_ONLY_API=no
VNC_SERVER_PASSWORD=myVncPassword
TWOFA_TIMEOUT_ACTION=restart
BYPASS_WARNING=
AUTO_RESTART_TIME=11:59 PM
AUTO_LOGOFF_TIME=
SAVE_TWS_SETTINGS=
RELOGIN_AFTER_2FA_TIMEOUT=yes
TIME_ZONE=Etc/UTC
CUSTOM_CONFIG=
SSH_TUNNEL=
SSH_OPTIONS=
SSH_ALIVE_INTERVAL=
SSH_ALIVE_COUNT=
SSH_PASSPHRASE=
SSH_REMOTE_PORT=
SSH_USER_TUNNEL=
SSH_RESTART=
SSH_VNC_PORT=
After running docker compose up --build
you can exec into the container and run your python script
❯ docker exec -it $(docker ps --latest --quiet) python3 code/main.py
date open high low close volume average barCount
0 2023-10-22 17:15:00-04:00 1.05970 1.05975 1.05950 1.05965 -1.0 -1.0 -1
1 2023-10-22 18:00:00-04:00 1.05965 1.05970 1.05890 1.05915 -1.0 -1.0 -1
2 2023-10-22 19:00:00-04:00 1.05915 1.05935 1.05885 1.05895 -1.0 -1.0 -1
3 2023-10-22 20:00:00-04:00 1.05895 1.05905 1.05840 1.05870 -1.0 -1.0 -1
4 2023-10-22 21:00:00-04:00 1.05870 1.05875 1.05820 1.05835 -1.0 -1.0 -1
.. ... ... ... ... ... ... ... ...
697 2023-11-30 18:00:00-05:00 1.08915 1.08945 1.08895 1.08920 -1.0 -1.0 -1
698 2023-11-30 19:00:00-05:00 1.08920 1.09030 1.08920 1.09020 -1.0 -1.0 -1
699 2023-11-30 20:00:00-05:00 1.09020 1.09100 1.09015 1.09070 -1.0 -1.0 -1
700 2023-11-30 21:00:00-05:00 1.09070 1.09130 1.09065 1.09075 -1.0 -1.0 -1
701 2023-11-30 22:00:00-05:00 1.09075 1.09095 1.08995 1.09010 -1.0 -1.0 -1
[702 rows x 8 columns]
Directory structure should look like this:
❯ tree
.
├── Pipfile
├── Pipfile.lock
├── Dockerfile
├── docker-compose.yml
├── code
│ ├── __init__.py
│ └── main.py
Hi @jcity
Glad to see you have it working.
I'll share a sample docker-compose.yml
with a different approach
This compose will
ib-gateway is not publishing any tws api port to the outside, jupyter and lago services can access ib-gateway on port 4003/4003
ib = IB()
ib.connect("ib-gateway", 4004, clientId=1) # host = service name
and the sample docker file
name: algo-trader
services:
ib-gateway:
restart: always
image: ghcr.io/gnzsnz/ib-gateway:stable
environment:
TWS_USERID: ${TWS_USERID}
TWS_PASSWORD: ${TWS_PASSWORD}
TRADING_MODE: ${TRADING_MODE:-paper}
# ... yada-yada-yada
ports:
#- "127.0.0.1:4001:4003" # don't share outside
#- "127.0.0.1:4002:4004"
- "127.0.0.1:5900:5900"
networks:
- quant
jupyterquant:
image: ghcr.io/gnzsnz/jupyter-quant:latest
environment:
APT_PROXY: ${APT_PROXY}
QB_CONF: ${QB_CONF}
# ... yada-yada-yada
networks:
- quant
volumes:
- ${PWD}/Documents/Notebooks:/home/gordon/Notebooks
ports:
- 8888:8888
algo:
image: python-based # for example your scripts
environment:
APT_PROXY: ${APT_PROXY}
QB_CONF: ${QB_CONF}
# ... yada-yada-yada
networks:
- quant
volumes_from:
- jupyterquant
ports:
- 8888:8888
networks:
- quant
this is just a sample, it won't work without modifications.
it's simpler to keep the ib-gateway or tws-rdesktop images as they are and just connect to the port. with this approach you can't connect to TWS api port from the outside (it's relatively safe)
hope it makes sense
@jcity regarding what migth be causing your errors
@gnzsnz thanks for the tips!
I like the approach you provided running the "python scripts" as a separate container and linking it with a network.
What I'm doing is essentially building a REST API (using FastAPI) as a "wrapper" over IBC. So I was about to go down the route of creating a new entrypoint that calls your start.sh
script and then starts the uvicorn
process after. I have that working but I think your approach is much cleaner so I'm going to give that a shot instead.
@jcity , if you feel that AcceptIncomingConnectionAction=accept
please let me know. and if possible provide error message, use cases, etc
I also had the errors above a lot. It actually means that you are trying to use the connection before it is established. The log for the port fork comes before the ibc is started in run.sh and once I see the log entry like
IBC: detected dialog entitled: DU******* Trader Workstation Configuration (Simulated Trading); event=Closed
I can use the connection to IB. Took me some time to find this, maybe it is of help for someone.
Happy New Year 2024 and thx a lot for providing and maintaining this repo!
@Mikkel84 , do you have reproduction steps? if so, could you please share them. I don't have this issue.
I also had the errors above a lot. It actually means that you are trying to use the connection before it is established. The log for the port fork comes before the ibc is started in run.sh and once I see the log entry like
IBC: detected dialog entitled: DU******* Trader Workstation Configuration (Simulated Trading); event=Closed
I can use the connection to IB. Took me some time to find this, maybe it is of help for someone.Happy New Year 2024 and thx a lot for providing and maintaining this repo!
Yes, it's great. I noticed that I need to confirm with my IB Key Authentication app before Docker can log in and allow me to connect.
Thanks, now that I read that again I understand. It only took me 5 months 🤣
Is your feature request related to a problem? Please describe. I am writing a helm chart to deploy this image. I was previously using https://github.com/rylorin/ib-gateway-docker but would prefer this one as it seems more fully maintained... Very many thanks for that by the way.
Describe the solution you'd like Just some help really figuring out what I migth be doing wrong. Maybe there is some nuance which needs special attention when running in Kubernetes
Describe alternatives you've considered As stated I already had everything up and running with rylorin/ib-gateway-docker. But long-term it seems better to make the move
Additional context Add any other context or screenshots about the feature request here.