"""
|
华鑫交易
|
"""
|
import hashlib
|
import json
|
import random
|
|
# 交易API
|
import socket
|
import time
|
|
# 交易订单号管理
|
import constant
|
from utils import tool
|
from db.redis_manager import RedisManager, RedisUtils
|
from log_module.log import logger_huaxin_trade
|
|
|
class TradeOrderIdManager:
|
__redisManager = RedisManager(2)
|
|
@classmethod
|
def __get_redis(cls):
|
return cls.__redisManager.getRedis()
|
|
# 添加订单ID
|
@classmethod
|
def add_order_id(cls, code, account_id, order_id):
|
RedisUtils.sadd(cls.__get_redis(), f"huaxin_order_id-{code}", json.dumps((account_id, order_id)))
|
RedisUtils.expire(cls.__get_redis(), f"huaxin_order_id-{code}", tool.get_expire())
|
|
# 删除订单ID
|
@classmethod
|
def remove_order_id(cls, code, account_id, order_id):
|
RedisUtils.srem(cls.__get_redis(), f"huaxin_order_id-{code}", json.dumps((account_id, order_id)))
|
|
# 查询所有的订单号
|
@classmethod
|
def list_order_ids(cls, code):
|
return RedisUtils.smembers(cls.__get_redis(), f"huaxin_order_id-{code}")
|
|
|
class TradeApi:
|
@classmethod
|
def __send_msg(cls, data):
|
if "req_id" not in data:
|
data["req_id"] = f"{round(time.time() * 1000)}_{random.randint(0, 10000)}"
|
# 签名
|
list_str = []
|
for k in data:
|
list_str.append(f"{k}={data[k]}")
|
list_str.sort()
|
__str = "&".join(list_str) + "JiaBei@!*."
|
md5 = hashlib.md5(__str.encode(encoding='utf-8')).hexdigest()
|
data["sign"] = md5
|
# 生成socket,连接server
|
ip_port = ("127.0.0.1", 9002) # server地址和端口号(最好是10000以后)
|
client = socket.socket() # 生成socket,连接server
|
client.connect(ip_port)
|
client.send(json.dumps(data).encode("utf-8"))
|
rec = client.recv(1024000)
|
result = rec.decode("gbk")
|
client.close()
|
return result
|
|
@classmethod
|
def buy(cls, code, count, price):
|
data = {"type": 0,
|
"data": json.dumps({"code": code, "count": count, "price": price})}
|
result = cls.__send_msg(data)
|
result = json.loads(result)
|
print("华鑫下单结果", result)
|
if result["code"] != 0:
|
raise Exception(result.get("msg"))
|
code_data = result["data"]
|
securityId = code_data["securityId"]
|
orderStatus = int(code_data["orderStatus"])
|
accountId = code_data["accountId"]
|
orderSysID = code_data["orderStatus"]
|
if orderStatus == 7:
|
raise Exception("交易所已拒绝")
|
return securityId, accountId, orderSysID
|
|
@classmethod
|
def cancel_buy(cls, code, order_sys_id):
|
data = {"type": 1,
|
"data": json.dumps({"code": code, "order_sys_id": order_sys_id})}
|
result = cls.__send_msg(data)
|
result = json.loads(result)
|
print("华鑫撤单结果", result)
|
if result["code"] != 0:
|
raise Exception(result.get("msg"))
|
result = result["data"]
|
if not result["cancel"]:
|
raise Exception(result.get("errorMsg"))
|
|
# 内容格式
|
# {"securityID": pOrderField.SecurityID, "orderLocalID": pOrderField.OrderLocalID,
|
# "direction": pOrderField.Direction, "orderSysID": pOrderField.OrderSysID,
|
# "insertTime": pOrderField.InsertTime, "insertDate": pOrderField.InsertDate,
|
# "acceptTime": pOrderField.AcceptTime, "cancelTime": pOrderField.CancelTime,
|
# "turnover": pOrderField.Turnover,
|
# "volume": pOrderField.VolumeTotalOriginal,
|
# "volumeTraded": pOrderField.VolumeTraded, "orderStatus": pOrderField.OrderStatus,
|
# "orderSubmitStatus": pOrderField.OrderSubmitStatus, "statusMsg": pOrderField.StatusMsg})
|
@classmethod
|
def list_delegate(cls):
|
data = {"type": 2}
|
result_str = cls.__send_msg(data)
|
result_json = json.loads(result_str)
|
if result_json["code"] != 0:
|
raise Exception(result_json.get("msg"))
|
return result_json["data"]
|
|
# 内容格式
|
# {"tradeID": pTradeField.TradeID, "securityID": pTradeField.SecurityID,
|
# "orderLocalID": pTradeField.OrderLocalID,
|
# "direction": pTradeField.Direction, "orderSysID": pTradeField.OrderSysID, "price": pTradeField.Price,
|
# "tradeTime": pTradeField.TradeTime,
|
# "volume": pTradeField.Volume, "tradeDate": pTradeField.TradeDate, "tradingDay": pTradeField.TradingDay,
|
# "PbuID": pTradeField.PbuID, "accountID": pTradeField.AccountID}
|
@classmethod
|
def list_traded(cls):
|
data = {"type": 3}
|
result = cls.__send_msg(data)
|
result_json = json.loads(result)
|
if result_json["code"] != 0:
|
raise Exception(result_json.get("msg"))
|
return result_json["data"]
|
|
|
# 通过量下单,返回(代码,账号ID,订单号)
|
def order_volume(code, price, count):
|
if not constant.TRADE_ENABLE:
|
return
|
if code.find("00") != 0 and code.find("60") != 0:
|
raise Exception("只支持00开头与60开头的代码下单")
|
start_time = time.time()
|
try:
|
securityId, accountId, orderSysID = TradeApi.buy(code, count, price)
|
print("华鑫下单耗时", time.time() - start_time)
|
logger_huaxin_trade.info(f"{code}:下单耗时{round(time.time() - start_time, 3)}s")
|
TradeOrderIdManager.add_order_id(code, accountId, orderSysID)
|
logger_huaxin_trade.info(f"{code}:下单成功 security_id:{securityId} ord_sys_id:{orderSysID}, accountId:{accountId}")
|
return securityId, accountId, orderSysID
|
except Exception as e:
|
logger_huaxin_trade.info(f"{code}:下单失败:{str(e)}")
|
raise e
|
|
|
# 撤单
|
def cancel_order(code):
|
orders_info = TradeOrderIdManager.list_order_ids(code)
|
if orders_info:
|
logger_huaxin_trade.info(f"{code}:开始执行撤单")
|
for order in orders_info:
|
order_info = json.loads(order)
|
# for i in range(3):
|
try:
|
TradeApi.cancel_buy(code, order_info[1])
|
except Exception as e:
|
# 状态异常表示已经撤单过了,不算无效撤单
|
if str(e).find("状态异常") < 0:
|
raise e
|
|
logger_huaxin_trade.info(f"{code}:撤单成功:{order_info}")
|
TradeOrderIdManager.remove_order_id(code, order_info[0], order_info[1])
|