-
Notifications
You must be signed in to change notification settings - Fork 3
/
data_source.py
283 lines (254 loc) · 12.5 KB
/
data_source.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
import asyncio
import re
from pydantic.types import Decimal
from models.bag_user import BagUser
from .stock_model import StockDB
# from .stock_log_model import StockLogDB
from configs.config import Config
from .utils import get_stock_info, get_total_value, to_obj, to_txt, is_a_stock, is_st_stock, get_tang_ping_earned
from services.log import logger
plugin_name = re.split(r'[\\/]', __file__)[-2]
async def buy_stock_action(user_id: int, group_id: int, stock_id: str, gearing: float, cost: int,
force_price: float = None) -> str:
infolist = await get_stock_info(stock_id)
if len(infolist) <= 7:
return f"未找到对应股票,提示:请使用股票代码而不是名字"
if force_price:
price = force_price
else:
price = float(infolist[3])
name = infolist[1]
lock = asyncio.Lock()
# 担心遇到线程问题,加了把锁(不知道有没有用)
async with lock:
have_gold = await BagUser.get_gold(user_id, group_id)
if have_gold <= 0 and gearing is None: # 先筛选一种情况
return f"你没有钱买股票"
if 0 < cost <= 10: # 如果花费小于10,认为他说的是仓位而不是花费
cost = have_gold * cost / 10
elif have_gold < cost:
return f"你当前只有{have_gold},买不起{cost}的股票哦"
if price == 0:
return f"{name}停牌了,不能买哦"
uid = f"{user_id}:{group_id}"
stock = await StockDB.get_stock(uid, stock_id)
# 先理清楚杠杆到底是多少
if stock:
if not gearing:
gearing = stock.gearing
if not gearing:
max_gearing = round(float(Config.get_config(plugin_name, "GEARING_RATIO", 5)), 1)
gearing = max_gearing
gearing = round(gearing, 1)
if (stock and have_gold == 0 and gearing == stock.gearing) or (stock is None and have_gold == 0):
return f"你没有钱买股票"
# 涨停的股票不能买可以做空 跌停的股票反之(A股特供,防止打板战术)
if is_a_stock(stock_id):
if is_st_stock(name):
if float(infolist[5]) > 4.93 and gearing >= 0:
return f"该股票涨停了,不能买哦"
if float(infolist[5]) < -4.93 and gearing < 0:
return f"该股票跌停了,不能做空哦"
if float(infolist[5]) > 9.9 and gearing >= 0:
return f"该股票涨停了,不能买哦"
if float(infolist[5]) < -9.9 and gearing < 0:
return f"该股票跌停了,不能做空哦"
num = cost / price
origin_cost = cost
if stock and stock.gearing != gearing: # 杠杆改变的逻辑
# 先把旧股票全卖了
earned = await fast_clear_stock(price, group_id, stock, user_id)
# 加上当前本金
cost = earned + cost
# 算出当前股数
num = cost / price
# 再买
query = await StockDB.buy_stock(
uid, stock_id, gearing, Decimal.from_float(num), Decimal.from_float(cost)
)
# await StockLogDB.buy_stock_log(uid, stock_id, gearing, num, price, cost)
await BagUser.spend_gold(user_id, group_id, cost)
if query:
price = Decimal.from_float(price).quantize(Decimal('0.001'))
if stock and stock.gearing != gearing:
return f'给{name}追加仓位{origin_cost},修改杠杆为{gearing}\n' \
f'因为杠杆的调整,持仓被重新计算了\n' \
f'现价 {price}块\n' \
f'当前持仓 {round(query.number / 100, 2)}手\n' \
f'当前持仓价值 {round((query.number * price - query.cost) * query.gearing + query.cost, 2)}\n' \
f'当前持仓成本 {round(query.cost, 2)}\n' \
f'杠杆比率 {query.gearing}\n' \
f'剩余资金 {round(have_gold - origin_cost)}'
else:
return f"成功购买了 {round(num / 100, 2)} 手 {name}\n" \
f"现价 {price}块\n" \
f"当前持仓 {round(query.number / 100, 2)}手\n" \
f"当前持仓价值 {round((query.number * price - query.cost) * query.gearing + query.cost, 2)}\n" \
f"当前持仓成本 {round(query.cost, 2)}\n" \
f"杠杆比率 {query.gearing}\n" \
f"剩余资金 {round(have_gold - cost)}"
# 快速清仓指令
async def fast_clear_stock(price, group_id, stock, user_id):
v = round(get_total_value(price, stock), 0)
# await StockLogDB.sell_stock_log(
# uid=f"{user_id}:{group_id}",
# stock_id=stock.stock_id,
# number=stock.number,
# price=price,
# get=v,
# profit=v - stock.cost)
await stock.delete()
await BagUser.add_gold(user_id, group_id, v)
return v
async def sell_stock_action(user_id: int, group_id: int, stock_id: str, percent: float,
force_price: float = None):
infolist = await get_stock_info(stock_id)
if len(infolist) <= 7:
return f"未找到对应股票,提示:请使用股票代码而不是名字"
logger.info(infolist)
if force_price:
price = force_price
else:
price = float(infolist[3])
name = infolist[1]
uid = f"{user_id}:{group_id}"
lock = asyncio.Lock()
# 担心遇到线程问题,加了把锁(不知道有没有用)
async with lock:
stock = await StockDB.get_stock(uid, stock_id)
if not stock:
return "你还没有买这个股票哦"
# 跌停的股票不能卖
if is_a_stock(stock_id):
if is_st_stock(name):
if float(infolist[5]) > 4.93 and stock.gearing > 0:
return f"{name}看起来跌停了,不能卖哦"
if float(infolist[5]) > 4.93 and stock.gearing < 0:
return f"{name}看起来涨停了,不能平仓哦"
if float(infolist[5]) < -9.9 and stock.gearing > 0:
return f"{name}看起来跌停了,不能卖哦"
if float(infolist[5]) > 9.9 and stock.gearing < 0:
return f"{name}看起来涨停了,不能平仓哦"
await StockDB.sell_stock(
uid, stock_id, percent
)
if stock.cost <= 0: # 正常情况不会出现,但是一旦出现需要异常修复
stock.cost = 1
total_value = get_total_value(price, stock)
return_money = round(total_value * percent / 10, 0)
earned_percent = round((total_value - float(stock.cost)) / float(stock.cost) * 100, 2)
# await StockLogDB.sell_stock_log(
# uid=uid,
# stock_id=stock_id,
# number=stock.number * percent / 10,
# price=price,
# get=return_money,
# profit=(total_value - stock.cost) * percent * stock.gearing)
await BagUser.add_gold(user_id, group_id, return_money)
if earned_percent < -100:
lajihua = f"亏了{-earned_percent}%,只能去当三和大神了!"
elif earned_percent < -10:
lajihua = f"亏了{-earned_percent}%,好伤心!"
elif earned_percent < 0:
lajihua = f"小亏了{-earned_percent}%"
elif earned_percent == 0:
lajihua = f"没亏没赚"
elif earned_percent < 5:
lajihua = f"小赚了{earned_percent}%"
elif earned_percent < 10:
lajihua = f"赚了{earned_percent}%,真开心!"
elif earned_percent < 50:
lajihua = f"赚了{earned_percent}%,赢麻了!"
elif earned_percent < 100:
lajihua = f"赚了{earned_percent}%,会所嫩模!"
else:
lajihua = f"赚了{earned_percent}%,正在通知管理员!"
return f"卖掉了 {name} {percent}成仓位, {lajihua}\n" \
f"成交价 {price}块\n" \
f"卖了 {return_money} 块钱\n" \
f"剩余仓位 {round(float(stock.number) * (1 - percent / 10) / 100, 2)} 手\n" \
f"剩余仓位当前价值 {round(float(total_value) * (1 - percent / 10), 2)}"
async def get_stock_list_action(uid: int, group_id: int):
my_stocks = await StockDB.get_my_stock(f"{uid}:{group_id}")
return [await to_obj(stock) for stock in my_stocks]
async def get_stock_list_action_for_win(uid: int, group_id: int):
my_stocks = await StockDB.get_my_stock(f"{uid}:{group_id}")
return [to_txt(await to_obj(stock)) for stock in my_stocks]
async def force_clear_action(user_id: int, group_id: int):
uid = f"{user_id}:{group_id}"
stocks = await StockDB.get_stocks_by_uid(uid)
tmp = ''
for stock in stocks:
if stock.stock_id == '躺平基金':
tmp += await sell_lazy_stock_action(user_id, group_id, 10)
else:
tmp += await sell_stock_action(user_id, group_id, stock.stock_id, 10)
tmp += '\n\n'
return len(stocks), tmp
async def revert_stock_action(user_id: int, group_id: int, stock_id: str):
infolist = await get_stock_info(stock_id)
if len(infolist) <= 7:
return f"未找到对应股票,提示:请使用股票代码而不是名字"
price = float(infolist[3])
name = infolist[1]
lock = asyncio.Lock()
# 担心遇到线程问题,加了把锁(不知道有没有用)
async with lock:
uid = f"{user_id}:{group_id}"
stock = await StockDB.get_stock(uid, stock_id)
if not stock:
return f"你还没买{name}(当前价格:{price})呢!"
gearing = -stock.gearing
if is_a_stock(stock_id):
if is_st_stock(name):
if float(infolist[5]) > 4.93 or float(infolist[5]) < -4.93:
return f"该功能在涨跌停时关闭!"
if float(infolist[5]) > 9.9 or float(infolist[5]) < -9.9:
return f"该功能在涨跌停时关闭!"
total_value = await fast_clear_stock(price, group_id, stock, user_id)
await buy_stock_action(user_id, group_id, stock_id, gearing, total_value, price)
return f"""反转{name}仓位成功!
当前股票价格{price}
当前杠杆{gearing}
当前仓位价值{total_value}
"""
async def buy_lazy_stock_action(user_id: int, group_id: int, cost: float):
lock = asyncio.Lock()
# 担心遇到线程问题,加了把锁(不知道有没有用)
async with lock:
have_gold = await BagUser.get_gold(user_id, group_id)
if cost <= 0:
return f"买入数量必须是正数哦(0-10:仓位 10+:价格)"
cost = cost if cost > 10 else round(have_gold * cost / 10, 0)
if cost <= 0 or have_gold - cost < 0 or have_gold <= 0:
return f"虽然你很想躺平,但是你没有足够的钱"
uid = f"{user_id}:{group_id}"
stock = await StockDB.get_stock(uid, "躺平基金")
# 如果一个人在10天前买了躺平,现在又买了10块钱,放进去会直接变成10/1.015^10块钱
if stock:
_, scale, _ = get_tang_ping_earned(stock, 10)
real_cost = cost / scale
else:
real_cost = cost
await BagUser.spend_gold(user_id, group_id, int(cost))
t = await StockDB.buy_stock(uid, "躺平基金", 1, Decimal.from_float(real_cost), Decimal.from_float(cost))
# await StockLogDB.buy_stock_log(uid, "躺平基金", 1, real_cost, 1, cost)
return f"欢迎认购躺平基金!您认购了💰{cost}的躺平基金,每待满一天就会获得" \
f"{round(float(Config.get_config(plugin_name, 'TANG_PING', 0.015) * 100), 1)}%的收益!一定要待满才有哦"
async def sell_lazy_stock_action(user_id: int, group_id: int, percent: float):
lock = asyncio.Lock()
# 担心遇到线程问题,加了把锁(不知道有没有用)
async with lock:
uid = f"{user_id}:{group_id}"
stock = await StockDB.get_stock(uid, "躺平基金")
if not stock:
return f"你之前不在躺平哦"
day, rate, earned = get_tang_ping_earned(stock, percent)
await stock.sell_stock(uid, "躺平基金", percent)
await BagUser.add_gold(user_id, group_id, earned)
# await StockLogDB.sell_stock_log(uid, "躺平基金", stock.number * percent / 10, 1, earned, earned / (1 + rate))
msg = f"坚持持有了{day}天所以翻了{round(rate, 2)}倍!(该倍率指最早一批买入资金的倍率)" if day > 0 else "没有坚持持有,只能把钱原路退给你了!"
return f"""卖出了{percent}成仓位的躺平基金
{msg}
得到了{earned}块钱
""".strip()