Skip to content

Commit

Permalink
Merge pull request #3 from Jedore/dev
Browse files Browse the repository at this point in the history
Add TTS simulation channel
  • Loading branch information
Jedore authored Jul 20, 2024
2 parents 6adb9a6 + d84ffbb commit 17ffab8
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 104 deletions.
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,14 @@

## 支持通道

- [x] TTS(tts)
- [x] openctp TTS(tts/tts-s)

[详情跳转1](https://github.com/openctp/openctp?tab=readme-ov-file#openctp%E6%A8%A1%E6%8B%9F%E7%8E%AF%E5%A2%83)
[详情跳转2](https://github.com/openctp/openctp/tree/master/ctp2TTS)

TTS仿真环境没有提供行情服务,需要连接实盘行情(连接实盘行情不需要替换dll/so), 因此多了一个 `tts-s` 通道

`tts` 通道用于连接 TTS 7x24 环境; `tts-s` 通道用于连接 TTS 仿真环境

| version | win x86 | win x64 | linux x64 |
|---------|--------------------|--------------------|--------------------|
Expand All @@ -61,7 +68,7 @@
| 6.7.1 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| 6.7.2 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |

- [x] 华鑫证券奇点TORA
- [x] 华鑫证券奇点股票(tora)

[详情跳转](https://github.com/openctp/openctp/tree/master/ctp2STP)

Expand Down Expand Up @@ -118,7 +125,6 @@

- [ ] 易盛
- [ ] 易达
- [ ] 东方证券OST
- [ ] 量投QDP

## 代码示例
Expand Down
6 changes: 6 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.1.4

- Add TTS simulation channel.
- Optimize func `switch`
- Optimize func `_copy_libs`

## 0.1.3

2024-07-19
Expand Down
2 changes: 1 addition & 1 deletion src/openctp_ctp_channels/__about__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.1.3'
__version__ = '0.1.4'
207 changes: 107 additions & 100 deletions src/openctp_ctp_channels/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
import requests

CHANNELS = {
'ctp': '上期技术',
'tts': 'openctp TTS',
'qq': '腾讯财经',
'sina': '新浪财经',
'ctp': '上期技术CTPAPI',
'tts': 'openctp TTS 7x24',
'tts-s': 'openctp TTS仿真(接实盘行情)',
'emt': '东方财富EMT',
'xtp': '中泰证券XTP',
'tora': '华鑫证券奇点TORA',
'tora': '华鑫证券奇点股票',
'qq': '腾讯财经(只有行情)',
'sina': '新浪财经(只有行情)',
}

BASE_DIR = Path(__file__).parent
Expand Down Expand Up @@ -47,6 +48,11 @@ def __init__(self, channel: str):
self._ctp_dir = BASE_DIR / '_chan_ctp'
self.check_ctp_dir()

# generate url
self._channel_url = self._base_url + '/' + self._channel
self._version_url = self._channel_url + '/' + self._ctp_version
self._platform_url = self._version_url + '/' + self._platform + '/'

@property
def channel(self):
return self._channel
Expand Down Expand Up @@ -164,15 +170,9 @@ def _download_libs(self):
self.download_lib(name, md5_string)

def _download(self):
self._generate_url()
self._check_channel_dir()
self._download_libs()

def _generate_url(self):
self._channel_url = self._base_url + '/' + self._channel
self._version_url = self._channel_url + '/' + self._ctp_version
self._platform_url = self._version_url + '/' + self._platform + '/'

def _backup(self):
lib_names = []
for _, _, filenames in os.walk(self._ctp_dir):
Expand Down Expand Up @@ -214,9 +214,21 @@ def _get_libs(self):

return tuple(lib_names)

@abc.abstractmethod
def switch(self):
raise NotImplementedError()
def switch(self, del_old: bool = True):
if self.current_channel() == self._channel:
print(f'Current channel is [ {self._channel} ]')
return

print(f'Switch to [ {self._channel} ]')

try:
self._download()
self._backup()
self._copy_libs(del_old=del_old)
except Exception as e:
print('Failed!', e)
else:
print('Succeeded!')

@staticmethod
def _channel_dirs():
Expand All @@ -232,26 +244,41 @@ def _delete_channel_dirs(self):
shutil.rmtree(channel_dir, ignore_errors=True)

def current_channel(self):
current_md5 = ''
mduser_md5 = ''
trader_md5 = ''
channel = 'ctp'
for file in os.listdir(self._ctp_lib_path):
if not file.startswith('thostmduser') and not file.startswith('libthostmduser'):
continue
with open(self._ctp_lib_path / file, 'rb') as f:
current_md5 = md5(f.read()).hexdigest()
if file.startswith('thostmduser') or file.startswith('libthostmduser'):
with open(self._ctp_lib_path / file, 'rb') as f:
mduser_md5 = md5(f.read()).hexdigest()
elif file.startswith('thosttrader') or file.startswith('libthosttrader'):
with open(self._ctp_lib_path / file, 'rb') as f:
trader_md5 = md5(f.read()).hexdigest()

for dir_path, dir_names, filenames in os.walk(BASE_DIR):
tmp_md5 = ''
tmp_mduser_md5 = ''
tmp_trader_md5 = ''
if not dir_names and filenames:
for filename in filenames:
if not filename.startswith('thostmduser') and not filename.startswith('libthostmduser'):
continue
with open(os.path.join(dir_path, filename), 'rb') as f:
tmp_md5 = md5(f.read()).hexdigest()
if tmp_md5 == current_md5:
if filename.startswith('thostmduser') or filename.startswith('libthostmduser'):
with open(os.path.join(dir_path, filename), 'rb') as f:
tmp_mduser_md5 = md5(f.read()).hexdigest()
elif filename.startswith('thosttrader') or filename.startswith('libthosttrader'):
with open(os.path.join(dir_path, filename), 'rb') as f:
tmp_trader_md5 = md5(f.read()).hexdigest()

if tmp_mduser_md5 == mduser_md5:
channel = os.path.basename(dir_path)[6:]
break

if not tmp_trader_md5:
# qq / sina
break
elif tmp_trader_md5 == trader_md5:
# ctp / emt / xtp / tora / tts
break
else:
# tts-s simulation
channel = 'tts-s'
break
return channel

def _del_old_files(self):
Expand Down Expand Up @@ -293,8 +320,9 @@ class CTPChannel(Channel):
def __init__(self):
super().__init__('ctp')

def _copy_libs(self):
self._del_old_files()
def _copy_libs(self, del_old: bool = True):
if del_old:
self._del_old_files()

for _, _, filenames in os.walk(self._channel_dir):
for filename in filenames:
Expand All @@ -310,84 +338,85 @@ def _copy_libs(self):

shutil.copyfile(src, dst)

def switch(self):
def switch(self, del_old: bool = True):
if self.current_channel() == self._channel:
print('Current channel is', self._channel)
print(f'Current channel is [ {self._channel} ]')
return

print(f'Switch to {self._channel} channel.')
self._copy_libs()
print(f'Switch to [ {self._channel} ]')
self._copy_libs(del_old=del_old)
print('Succeeded!')


class TTSChannel(Channel):

def __init__(self):
super().__init__('tts')

def switch(self):
if self.current_channel() == self._channel:
print('Current channel is', self._channel)
return

print(f'Switch to {self._channel} channel.')
class TTSSimuChannel(Channel):

def __init__(self):
super().__init__('tts')
self._channel = 'tts-s'

def switch(self, del_old: bool = True):
super().switch(del_old)

def _copy_libs(self, del_old: bool = True):
if del_old:
self._del_old_files()

lib_dict = {}
for lib_name in self._get_libs():
s1, s2 = lib_name.split('-')
s3, s4 = s2.split('.')
lib_dict[f'{s1}.{s4}'] = lib_name

for _, _, filenames in os.walk(self._channel_dir):
for filename in filenames:
if self._check_lib_prefix(filename):
continue

dst_name = lib_dict[filename]
dst = self._ctp_lib_path / dst_name

if self._platform.startswith('linux'):
if os.path.exists(dst):
os.remove(dst)

self._download()
self._backup()
self._copy_libs()
if 'mduser' in filename:
# copy mduserapi dll/so from ctp
shutil.copyfile(self._ctp_dir / dst_name, dst)
else:
shutil.copyfile(self._channel_dir / filename, dst)


class QQChannel(Channel):

def __init__(self):
super().__init__('qq')

def switch(self):
if self.current_channel() == self._channel:
print('Current channel is', self._channel)
return

print(f'Switch to {self._channel} channel.')

self._download()
self._backup()
self._copy_libs(del_old=False)
def switch(self, del_old: bool = False):
super().switch(del_old=del_old)


class SinaChannel(Channel):

def __init__(self):
super().__init__('sina')

def switch(self):
if self.current_channel() == self._channel:
print('Current channel is', self._channel)
return

print(f'Switch to {self._channel} channel.')

self._download()
self._backup()
self._copy_libs(del_old=False)
def switch(self, del_old: bool = False):
super().switch(del_old=del_old)


class EMTChannel(Channel):

def __init__(self):
super().__init__('emt')

def switch(self):
if self.current_channel() == self._channel:
print('Current channel is', self._channel)
return

print(f'Switch to {self._channel} channel.')

self._download()
self._backup()
self._copy_libs()

def _copy_libs(self):
super()._copy_libs()
def _copy_libs(self, del_old: bool = True):
super()._copy_libs(del_old=del_old)
self._copy_files(['emt_api.dll', 'emt_quote_api.dll'])


Expand All @@ -396,19 +425,8 @@ class XTPChannel(Channel):
def __init__(self):
super().__init__('xtp')

def switch(self):
if self.current_channel() == self._channel:
print('Current channel is', self._channel)
return

print(f'Switch to {self._channel} channel.')

self._download()
self._backup()
self._copy_libs()

def _copy_libs(self):
super()._copy_libs()
def _copy_libs(self, del_old: bool = True):
super()._copy_libs(del_old=del_old)
if sys.platform.startswith('linux'):
files = ['libxtpquoteapi.so', 'libxtptraderapi.so']
else:
Expand All @@ -421,19 +439,8 @@ class ToraChannel(Channel):
def __init__(self):
super().__init__('tora')

def switch(self):
if self.current_channel() == self._channel:
print('Current channel is', self._channel)
return

print(f'Switch to {self._channel} channel.')

self._download()
self._backup()
self._copy_libs()

def _copy_libs(self):
super()._copy_libs()
def _copy_libs(self, del_old=True):
super()._copy_libs(del_old=del_old)
if sys.platform.startswith('linux'):
files = ['libfasttraderapi.so', 'libxfastmdapi.so']
else:
Expand Down
2 changes: 2 additions & 0 deletions src/openctp_ctp_channels/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ def check():
def switch(channel):
if 'tts' == channel:
channel = channels.TTSChannel()
elif 'tts-s' == channel:
channel = channels.TTSSimuChannel()
elif 'ctp' == channel:
channel = channels.CTPChannel()
elif 'qq' == channel:
Expand Down

0 comments on commit 17ffab8

Please sign in to comment.