Skip to content

Commit 41bbbe5

Browse files
authored
Merge pull request #31 from LukeWang01/dev
improvement fix
2 parents 579b397 + 82634e9 commit 41bbbe5

File tree

7 files changed

+181
-88
lines changed

7 files changed

+181
-88
lines changed

brokers/ibkr_broker.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
import nest_asyncio
1616

17+
from trading_settings import TRADING_ALLOW_PRE_POST_MARKET_ORDER
18+
1719
nest_asyncio.apply()
1820

1921
""" ⬇️ Broker Setup ⬇️ """
@@ -38,7 +40,7 @@
3840
Step 3: Set up the trading information
3941
'''
4042
# TODO: Set up the trading information for pre post market trading
41-
FILL_OUTSIDE_MARKET_HOURS = True # enable if order fills on extended hours
43+
FILL_OUTSIDE_MARKET_HOURS = TRADING_ALLOW_PRE_POST_MARKET_ORDER # enable if order fills on extended hours
4244

4345
""" ⏫ Broker Setup ⏫ """
4446

@@ -189,7 +191,7 @@ def limit_sell(self, stock: str, quantity: int, price: float):
189191

190192
try:
191193
contract = Stock(stock, 'SMART', 'USD')
192-
order = LimitOrder('sell', quantity, price, account=IBKR_ACCOUNT_NUMBER)
194+
order = LimitOrder('sell', quantity, price, account=IBKR_ACCOUNT_NUMBER, outsideRth=FILL_OUTSIDE_MARKET_HOURS)
193195
trade = self.ib.placeOrder(contract, order)
194196
return self.ret_ok_code, None
195197
except Exception as e:
@@ -207,8 +209,9 @@ def limit_buy(self, stock: str, quantity: int, price: float):
207209

208210
try:
209211
contract = Stock(stock, 'SMART', 'USD')
210-
order = LimitOrder('buy', quantity, price, account=IBKR_ACCOUNT_NUMBER)
212+
order = LimitOrder('buy', quantity, price, account=IBKR_ACCOUNT_NUMBER, outsideRth=FILL_OUTSIDE_MARKET_HOURS)
211213
trade = self.ib.placeOrder(contract, order)
214+
res = f"Trade submitted: {trade}"
212215
return self.ret_ok_code, None
213216
except Exception as e:
214217
self.logger.error(f"Error placing limit buy order: {e}")

brokers/moomoo_futu_broker.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
from brokers.base_broker import BaseBroker
2929
from env._secrete import MooMoo_Futu_PWD, MooMoo_Futu_SecurityFirm
30-
from trading_settings import TRADING_BROKER
30+
from trading_settings import TRADING_BROKER, TRADING_ALLOW_PRE_POST_MARKET_ORDER
3131
from utils.wall_api_client import print_status
3232

3333
import nest_asyncio
@@ -53,7 +53,7 @@
5353
'''
5454
Step 3: Set up the trading information
5555
'''
56-
FILL_OUTSIDE_MARKET_HOURS = True # enable if order fills on extended hours
56+
FILL_OUTSIDE_MARKET_HOURS = TRADING_ALLOW_PRE_POST_MARKET_ORDER # enable if order fills on extended hours
5757
TRADING_MARKET = TrdMarket.US # set up the trading market, US market, HK for HongKong, etc.
5858
# NONE = "N/A"
5959
# HK = "HK"

brokers/schwab_broker.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import httpx
2020
import time
2121

22+
from trading_settings import TRADING_ALLOW_PRE_POST_MARKET_ORDER
23+
2224
""" ⬇️ Broker Setup ⬇️ """
2325
# Schwab API Docs: https://schwab-py.readthedocs.io/en/latest/getting-started.html
2426
'''
@@ -38,7 +40,7 @@
3840
'''
3941
Step 3: Set up the trading information
4042
'''
41-
FILL_OUTSIDE_MARKET_HOURS = True # enable if order fills on extended hours
43+
FILL_OUTSIDE_MARKET_HOURS = TRADING_ALLOW_PRE_POST_MARKET_ORDER # enable if order fills on extended hours
4244

4345
""" ⏫ Broker Setup ⏫ """
4446

brokers/webull_broker.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@
1111
from webull import webull
1212

1313
from brokers.base_broker import BaseBroker
14+
from trading_settings import TRADING_ALLOW_PRE_POST_MARKET_ORDER
1415
from utils.time_tool import get_current_time
1516

1617
""" ⬇️ Broker Setup ⬇️ """
1718
# refill the setup like MooMooFutuBroker Class
19+
20+
FILL_OUTSIDE_MARKET_HOURS = TRADING_ALLOW_PRE_POST_MARKET_ORDER # enable if order fills on extended hours
21+
1822
""" ⏫ Broker Setup ⏫ """
1923

2024

run_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
from brokers.broker_factory import BrokerFactory
66
from env._secrete import SERVER_IP, API_CLIENT_ID, API_PASSWORD
7-
from trading_settings import decision_qty, TRADING_BROKER, TRADING_CONFIRMATION
7+
from trading_settings import TRADING_BROKER, TRADING_CONFIRMATION
8+
from utils.local_decision import decision_qty
89
from utils.wall_api_client import DataClient, print_status
910
from utils.logger_config import setup_logger
1011

trading_settings.py

Lines changed: 23 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
# Description: This file contains the settings for trading.
2-
from utils.wall_api_client import print_status
3-
42

53
""" Step 1: ‼️ Important. Set up the broker name ‼️ """
64
TRADING_BROKER = 'MooMoo' # set up the broker name based on the broker class name
@@ -12,7 +10,6 @@
1210
'SCHWAB': SchwabBroker,
1311
"""
1412

15-
1613
""" Step 2: ‼️ Important. Please choose qty decision mode, revise qty setting for each stock ‼️ """
1714
# Option 1: FUND_MODE, calculate the trading quantity based on the initial fund
1815
FUND_MODE = True # default to True, set to False if you want to use fixed qty
@@ -26,112 +23,57 @@
2623
ONE_PERCENT_TRADING_QTY_FOR_SOXL = 1 # default to 1, set the trading quantity for 1% of the initial fund
2724
ONE_PERCENT_TRADING_QTY_FOR_IBIT = 1 # default to 1, set the trading quantity for 1% of the initial fund
2825

29-
3026
""" Step 3: ‼️ Important. Please choose which level and which ticker you want to trade ‼️ """
3127
TRADING_LIST = ['TQQQ', 'SOXL', 'IBIT'] # set the trading list, delete the stock if you don't want to trade
3228
TRADING_LEVEL = ['L0', 'L1', 'L2', 'L3', 'L4'] # set the trading level, delete the level if you don't want to trade
3329

34-
35-
""" Step 4 (Optional): Account settings, don't change the default setting unless you know what you are doing """
30+
""" (Optional): Account settings, don't change the default setting unless you know what you are doing """
3631
TRADING_CONFIRMATION = True # default to True, set to False if you want to stop trading
3732
TRADING_CASH_THRESHOLD = 1 # set the minimum cash balance requirement after each trade
3833
TRADING_CASH_MARGIN_CONTROL = True # default to True, set to False if you want to use margin
3934
TRADING_ALLOW_PRE_POST_MARKET_ORDER = True # default to True, set to False if you don't want to trade in pre/post market
4035

41-
4236
""" Please don't change the code below, unless you know what you are doing """
43-
level_positions = {
37+
""" Specific Trading Control Settings """
38+
# trading position control:
39+
LEVEL_POSITIONS = {
4440
# this is the default setting, which corresponds to the trading strategy for WallTrading Bot
4541
# please don't change the default setting, unless you know what you are doing
4642
# please contact the dev team for any questions
4743
0: { # L0
4844
'depth': {0: 0.01, 1: 0.01, 2: 0.01, 3: 0.00, 4: 0.00, 5: 0.02, 6: 0.02, 7: 0.03, 8: 0.04, 9: 0.04, 10: 0.05},
49-
'code': {3: 0.02}
45+
'code': {3: 0.02},
46+
'enable': True # default to True, set to False if you don't want to trade at this level
5047
},
5148
1: { # L1
5249
'depth': {0: 0.01, 1: 0.01, 2: 0.01, 3: 0.00, 4: 0.00, 5: 0.02, 6: 0.02, 7: 0.03, 8: 0.04, 9: 0.04, 10: 0.05},
53-
'code': {3: 0.03}
50+
'code': {3: 0.03},
51+
'enable': True # default to True, set to False if you don't want to trade at this level
5452
},
5553
2: { # L2
5654
'depth': {0: 0.02, 1: 0.02, 2: 0.02, 3: 0.00, 4: 0.00, 5: 0.00, 6: 0.04, 7: 0.04, 8: 0.05, 9: 0.06, 10: 0.07},
57-
'code': {3: 0.04}
55+
'code': {3: 0.04},
56+
'enable': True # default to True, set to False if you don't want to trade at this level
5857
},
5958
3: { # L3
6059
'depth': {0: 0.03, 1: 0.03, 2: 0.03, 3: 0.04, 4: 0.08, 5: 0.00, 6: 0.00, 7: 0.00, 8: 0.00, 9: 0.00, 10: 0.00},
61-
'code': {3: 0.08}
60+
'code': {3: 0.08},
61+
'enable': True # default to True, set to False if you don't want to trade at this level
6262
},
6363
4: { # L4
6464
'depth': {0: 0.15, 1: 0.22, 2: 0.22, 3: 0.25, 4: 0.25, 5: 0.00, 6: 0.00, 7: 0.00, 8: 0.00, 9: 0.00, 10: 0.00},
65-
'code': {3: 0.22}
65+
'code': {3: 0.22},
66+
'enable': True # default to True, set to False if you don't want to trade at this level
6667
}
6768
}
6869

69-
""" Please don't change the code below: """
70-
71-
72-
def decision_qty(json_data) -> tuple[int, float]:
73-
"""
74-
:param json_data:
75-
:return: qty, position_pct
76-
"""
77-
78-
level = int(json_data["level"][1:])
79-
depth = int(json_data["depth"])
80-
codeNum = int(json_data["codeNum"])
81-
price = float(json_data["price"])
82-
83-
position_pct = 0
84-
85-
if level in level_positions:
86-
if depth in level_positions[level]['depth']:
87-
position_pct += level_positions[level]['depth'][depth]
88-
if codeNum in level_positions[level]['code']:
89-
position_pct += level_positions[level]['code'][codeNum]
90-
91-
# check if the trading data is in the trading list and trading level
92-
if json_data["ticker"] not in TRADING_LIST:
93-
print_status("Decision QTY Handler", f"Warning, ticker not in the trading list, qty is 0, please check the trading settings", "WARNING")
94-
return 0, position_pct
95-
if json_data["level"] not in TRADING_LEVEL:
96-
print_status("Decision QTY Handler", f"Warning, level not in the trading level, qty is 0, please check the trading settings", "WARNING")
97-
return 0, position_pct
98-
99-
# calculate the trading quantity, FUND_MODE
100-
if FUND_MODE:
101-
initial_fund = 0
102-
103-
if json_data["ticker"] == "TQQQ":
104-
initial_fund = INITIAL_FUND_FOR_TQQQ
105-
elif json_data["ticker"] == "SOXL":
106-
initial_fund = INITIAL_FUND_FOR_SOXL
107-
elif json_data["ticker"] == "IBIT":
108-
initial_fund = INITIAL_FUND_FOR_IBIT
109-
qty = int((position_pct * initial_fund) / price)
110-
# if qty < 1:
111-
# qty = 1
112-
# print_status("Decision QTY Handler - FUND MODE", f"Warning, qty reset to: {qty}, please check the trading settings", "WARNING")
113-
# delete, choose to strictly follow the position percentage
114-
print_status("Decision QTY Handler - FUND MODE", f"Decision, qty is {qty}, please check the trading settings", "INFO")
115-
return qty, position_pct
116-
117-
# calculate the trading quantity, QTY_MODE
118-
elif QTY_MODE:
119-
qty_one_percent = 1
120-
if json_data["ticker"] == "TQQQ":
121-
qty_one_percent = ONE_PERCENT_TRADING_QTY_FOR_TQQQ
122-
elif json_data["ticker"] == "SOXL":
123-
qty_one_percent = ONE_PERCENT_TRADING_QTY_FOR_SOXL
124-
elif json_data["ticker"] == "IBIT":
125-
qty_one_percent = ONE_PERCENT_TRADING_QTY_FOR_IBIT
126-
qty = int(position_pct * 100) * qty_one_percent
127-
# if qty < 1:
128-
# qty = 1
129-
# print_status("Decision QTY Handler - QTY MODE", f"Warning, qty reset to: {qty}, please check the trading settings", "WARNING")
130-
# delete, choose to strictly follow the position percentage
131-
print_status("Decision QTY Handler - QTY MODE", f"Decision, qty is {qty}, please check the trading settings", "INFO")
132-
return qty, position_pct
70+
# trading direction control:
71+
# buy side
72+
ENABLE_BUY_TQQQ = True # default to True, set to False if you don't want to buy TQQQ
73+
ENABLE_BUY_SOXL = True # default to True, set to False if you don't want to buy SOXL
74+
ENABLE_BUY_IBIT = True # default to True, set to False if you don't want to buy IBIT
75+
# sell side
76+
ENABLE_SELL_TQQQ = True # default to True, set to False if you don't want to sell TQQQ
77+
ENABLE_SELL_SOXL = True # default to True, set to False if you don't want to sell SOXL
78+
ENABLE_SELL_IBIT = True # default to True, set to False if you don't want to sell IBIT
13379

134-
else:
135-
print_status("Decision QTY Handler", f"Warning, wrong decision mode, qty is 0, please check the trading settings",
136-
"WARNING")
137-
return 0, position_pct

utils/local_decision.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
""" Please don't change the code below, unless you know what you are doing """
2+
3+
from trading_settings import LEVEL_POSITIONS, TRADING_LIST, TRADING_LEVEL, ENABLE_BUY_TQQQ, ENABLE_BUY_SOXL, \
4+
ENABLE_BUY_IBIT, ENABLE_SELL_TQQQ, ENABLE_SELL_SOXL, ENABLE_SELL_IBIT, FUND_MODE, INITIAL_FUND_FOR_TQQQ, \
5+
INITIAL_FUND_FOR_SOXL, INITIAL_FUND_FOR_IBIT, QTY_MODE, ONE_PERCENT_TRADING_QTY_FOR_TQQQ, \
6+
ONE_PERCENT_TRADING_QTY_FOR_SOXL, ONE_PERCENT_TRADING_QTY_FOR_IBIT
7+
from utils.wall_api_client import print_status
8+
9+
"""
10+
Local decision handler for the trade
11+
"""
12+
13+
""" Please do NOT change the code below, unless you KNOW what you are doing """
14+
15+
16+
def decision_qty(json_data) -> tuple[int, float]:
17+
"""
18+
:param json_data:
19+
:return: qty, position_pct
20+
"""
21+
22+
level = int(json_data["level"][1:])
23+
depth = int(json_data["depth"])
24+
codeNum = int(json_data["codeNum"])
25+
price = float(json_data["price"])
26+
stock = json_data["ticker"]
27+
direction = json_data["direction"]
28+
29+
position_pct = 0
30+
31+
# 0. # calculate the position percentage and check level
32+
if level in LEVEL_POSITIONS:
33+
# calculate the position percentage
34+
if depth in LEVEL_POSITIONS[level]['depth']:
35+
position_pct += LEVEL_POSITIONS[level]['depth'][depth]
36+
if codeNum in LEVEL_POSITIONS[level]['code']:
37+
position_pct += LEVEL_POSITIONS[level]['code'][codeNum]
38+
39+
# check if the current level is enabled
40+
if not LEVEL_POSITIONS[level]['enable']:
41+
print_status("Decision QTY Handler",
42+
f"Decision, level: {level}, not enabled, qty is 0, please check the trading settings",
43+
"WARNING")
44+
return 0, position_pct
45+
else:
46+
print_status("Decision QTY Handler",
47+
f"Warning, level issues, qty is 0, please check the trading settings",
48+
"WARNING")
49+
return 0, position_pct
50+
51+
# 1. check if the trading data is in the trading list and trading level
52+
if stock not in TRADING_LIST:
53+
print_status("Decision QTY Handler",
54+
f"Warning, ticker not in the trading list, qty is 0, please check the trading settings",
55+
"WARNING")
56+
return 0, position_pct
57+
if json_data["level"] not in TRADING_LEVEL:
58+
print_status("Decision QTY Handler",
59+
f"Warning, level not in the trading level, qty is 0, please check the trading settings",
60+
"WARNING")
61+
return 0, position_pct
62+
63+
# 2. check if the trading direction is enabled
64+
if direction == "Bull":
65+
if stock == "TQQQ" and not ENABLE_BUY_TQQQ:
66+
print_status("Decision QTY Handler",
67+
f"Warning, {stock} buy is not enabled, qty is 0, please check the trading settings",
68+
"WARNING")
69+
return 0, position_pct
70+
if stock == "SOXL" and not ENABLE_BUY_SOXL:
71+
print_status("Decision QTY Handler",
72+
f"Warning, {stock} buy is not enabled, qty is 0, please check the trading settings",
73+
"WARNING")
74+
return 0, position_pct
75+
if stock == "IBIT" and not ENABLE_BUY_IBIT:
76+
print_status("Decision QTY Handler",
77+
f"Warning, {stock} buy is not enabled, qty is 0, please check the trading settings",
78+
"WARNING")
79+
return 0, position_pct
80+
elif direction == "Bear":
81+
if stock == "TQQQ" and not ENABLE_SELL_TQQQ:
82+
print_status("Decision QTY Handler",
83+
f"Warning, {stock} sell is not enabled, qty is 0, please check the trading settings",
84+
"WARNING")
85+
return 0, position_pct
86+
if stock == "SOXL" and not ENABLE_SELL_SOXL:
87+
print_status("Decision QTY Handler",
88+
f"Warning, {stock} sell is not enabled, qty is 0, please check the trading settings",
89+
"WARNING")
90+
return 0, position_pct
91+
if stock == "IBIT" and not ENABLE_SELL_IBIT:
92+
print_status("Decision QTY Handler",
93+
f"Warning, {stock} sell is not enabled, qty is 0, please check the trading settings",
94+
"WARNING")
95+
return 0, position_pct
96+
97+
# 3. calculate the trading quantity
98+
# 3.1 calculate the trading quantity, FUND_MODE
99+
if FUND_MODE:
100+
initial_fund = 0
101+
102+
if stock == "TQQQ":
103+
initial_fund = INITIAL_FUND_FOR_TQQQ
104+
elif stock == "SOXL":
105+
initial_fund = INITIAL_FUND_FOR_SOXL
106+
elif stock == "IBIT":
107+
initial_fund = INITIAL_FUND_FOR_IBIT
108+
qty = int((position_pct * initial_fund) / price)
109+
# if qty < 1:
110+
# qty = 1
111+
# print_status("Decision QTY Handler - FUND MODE", f"Warning, qty reset to: {qty}, please check the trading settings", "WARNING")
112+
# delete, choose to strictly follow the position percentage
113+
print_status("Decision QTY Handler - FUND MODE",
114+
f"Decision, qty is {qty}, please check the trading settings",
115+
"INFO")
116+
return qty, position_pct
117+
118+
# 3.2calculate the trading quantity, QTY_MODE
119+
elif QTY_MODE:
120+
qty_one_percent = 1
121+
if stock == "TQQQ":
122+
qty_one_percent = ONE_PERCENT_TRADING_QTY_FOR_TQQQ
123+
elif stock == "SOXL":
124+
qty_one_percent = ONE_PERCENT_TRADING_QTY_FOR_SOXL
125+
elif stock == "IBIT":
126+
qty_one_percent = ONE_PERCENT_TRADING_QTY_FOR_IBIT
127+
qty = int(position_pct * 100) * qty_one_percent
128+
# if qty < 1:
129+
# qty = 1
130+
# print_status("Decision QTY Handler - QTY MODE", f"Warning, qty reset to: {qty}, please check the trading settings", "WARNING")
131+
# qty reset deleted, choose to strictly follow the position percentage
132+
print_status("Decision QTY Handler - QTY MODE",
133+
f"Decision, qty is {qty}, please check the trading settings",
134+
"INFO")
135+
return qty, position_pct
136+
137+
else:
138+
print_status("Decision QTY Handler",
139+
f"Warning, wrong decision mode, qty is 0, please check the trading settings",
140+
"WARNING")
141+
return 0, position_pct

0 commit comments

Comments
 (0)