def run_tianqin_code(bid, user_id, pwd, td_url): api = TqApi(TqAccount(bid, user_id, pwd), auth="[email protected],MaYanQiong", _stock=True, _td_url=td_url, debug="c.log") is_ctp = False if bid == "快期模拟" else True account = api.get_account() if bid == "快期模拟": assert account.ctp_balance == '-' or math.isnan(account.ctp_balance) assert account.ctp_available == '-' or math.isnan( account.ctp_available) else: logger.info(f"{account.ctp_balance}, {account.ctp_available}") logger.info(f"{'='*30} 登录成功后,账户初始状态 {'='*30}") positions = api._data["trade"][user_id]["positions"] orders = api._data["trade"][user_id]["orders"] check_orders(orders, api, is_ctp) check_positions(positions, api, is_ctp) check_account(account, positions, is_ctp) check_risk_rule(api, None) check_risk_data(api, "SSE.10002504") api.set_risk_management_rule("SZSE", True) logger.info(f"{'='*12} 期权 开仓 {'='*12}") # quote = api.get_quote("SZSE.91000999") # ETF 期权 SSE.10002504 # print(quote) # 挂单 # order = api.insert_order(symbol="SSE.10002504", direction="BUY", offset="OPEN", limit_price=quote.lower_limit + quote.price_tick, volume=2) # order = api.insert_order(symbol="SSE.10002504", direction="SELL", offset="OPEN", limit_price=quote.upper_limit - quote.price_tick, volume=2) # 可成交 # order = api.insert_order(symbol="SSE.10002513", direction="BUY", offset="OPEN", limit_price=quote.ask_price1, volume=3) # 可成交 FAK 下单失败,CTP:交易所不支持的价格类型 # order = api.insert_order(symbol="SSE.10002513", direction="BUY", offset="OPEN", limit_price=quote.ask_price1, volume=2, advanced="FAK") # 可成交 FOK # order = api.insert_order(symbol="SSE.10002513", direction="BUY", offset="OPEN", limit_price=quote.ask_price1, volume=2, advanced="FOK") # BEST order = api.insert_order(symbol="SZSE.91000999", direction="BUY", offset="OPEN", limit_price="BEST", volume=5) # BEST FOK 下单失败,已撤单报单被拒绝12038,合约代码:SSE.10002513,下单方向:买,开平标志:开仓,委托价格:最优价,委托手数:3 # order = api.insert_order(symbol="SSE.10002513", direction="SELL", offset="CLOSE", limit_price="BEST", volume=3, advanced="FOK") # any_price 通知: 下单失败,CTP:交易所不支持的价格类型 # order = api.insert_order(symbol="SSE.10002513", direction="BUY", offset="OPEN", volume=3) # FIVELEVEL 通知: 下单失败,CTP:交易所不支持的价格类型 # order = api.insert_order(symbol="SSE.10002513", direction="BUY", offset="OPEN", limit_price="FIVELEVEL", volume=3) api.wait_update() # api.cancel_order(order) while order.status == "ALIVE": api.wait_update() check_all(api, bid, user_id) # check_risk_rule(api,None) check_risk_data(api, "SZSE.91000999") api.close()
def test_get_account(self): """ 获取账户资金信息 """ # 预设服务器端响应 dir_path = os.path.dirname(os.path.realpath(__file__)) self.mock.run( os.path.join(dir_path, "log_file", "test_td_basic_get_account_simulate.script.lzma")) # 测试: 获取数据 api = TqApi(_ins_url=self.ins_url, _td_url=self.td_url, _md_url=self.md_url) TqApi.RD = random.Random(4) order = api.insert_order("DCE.jd2001", "BUY", "OPEN", 1, limit_price=4570) while order.status == "ALIVE": api.wait_update() account = api.get_account() # 测试脚本重新生成后,数据根据实际情况有变化 self.assertEqual( str(account), "{'currency': 'CNY', 'pre_balance': 10000000.0, 'static_balance': 10000000.0, 'balance': 9994873.877, 'available': 9992016.477, 'float_profit': -5120.0, 'position_profit': -5120.0, 'close_profit': 0.0, 'frozen_margin': 0.0, 'margin': 2857.4, 'frozen_commission': 0.0, 'commission': 6.122999999999999, 'frozen_premium': 0.0, 'premium': 0.0, 'deposit': 0.0, 'withdraw': 0.0, 'risk_ratio': 0.00028588654896140217}" ) self.assertEqual(account.currency, "CNY") self.assertEqual(account.pre_balance, 10000000.0) self.assertEqual(9994873.877, account.balance) self.assertEqual(6.122999999999999, account["commission"]) self.assertEqual(2857.4, account["margin"]) self.assertEqual(-5120.0, account.position_profit) api.close()
def test_get_account(self): """ 获取账户资金信息 """ # 预设服务器端响应 self.mock.run("test_td_basic_get_account_simulate.script") # 测试: 获取数据 api = TqApi(_ins_url=self.ins_url, _td_url=self.td_url, _md_url=self.md_url) TqApi.RD = random.Random(4) order = api.insert_order("DCE.jd2001", "BUY", "OPEN", 1, limit_price=4570) while order.status == "ALIVE": api.wait_update() account = api.get_account() self.assertEqual( str(account), "{'currency': 'CNY', 'pre_balance': 10000000.0, 'static_balance': 10000000.0, 'balance': 9999973.877, 'available': 9997116.477, 'float_profit': -20.0, 'position_profit': -20.0, 'close_profit': 0.0, 'frozen_margin': 0.0, 'margin': 2857.4, 'frozen_commission': 0.0, 'commission': 6.122999999999999, 'frozen_premium': 0.0, 'premium': 0.0, 'deposit': 0.0, 'withdraw': 0.0, 'risk_ratio': 0.00028574074644055193}" ) self.assertEqual(account.currency, "CNY") self.assertEqual(account.pre_balance, 10000000.0) self.assertEqual(9999973.877, account.balance) self.assertEqual(6.122999999999999, account["commission"]) self.assertEqual(2857.4, account["margin"]) self.assertEqual(-20.0, account.position_profit) api.close()
def test_get_account_option(self): """ 获取账户资金信息 """ # 预设服务器端响应 dir_path = os.path.dirname(os.path.realpath(__file__)) self.mock.run( os.path.join( dir_path, "log_file", "test_td_basic_get_account_simulate_option.script.lzma")) # 测试: 获取数据 api = TqApi(_ins_url=self.ins_url_2020_04_02, _td_url=self.td_url, _md_url=self.md_url) utils.RD = random.Random(4) order1 = api.insert_order("CZCE.SR007C5600", "SELL", "OPEN", 2, limit_price=50) order2 = api.insert_order("DCE.m2007-P-2900", "BUY", "OPEN", 3, limit_price=180) while order1.status == "ALIVE" or order2.status == "ALIVE": api.wait_update() account = api.get_account() # 测试脚本重新生成后,数据根据实际情况有变化 self.assertEqual( str(account), "{'currency': 'CNY', 'pre_balance': 10000000.0, 'static_balance': 10000000.0, 'balance': 9998650.0, 'available': 9989752.8, 'ctp_balance': nan, 'ctp_available': nan, 'float_profit': -300.0, 'position_profit': 0.0, 'close_profit': 0.0, 'frozen_margin': 0.0, 'margin': 4797.200000000001, 'frozen_commission': 0.0, 'commission': 50.0, 'frozen_premium': 0.0, 'premium': -5400.0, 'deposit': 0.0, 'withdraw': 0.0, 'risk_ratio': 0.00047978477094407754, 'market_value': 4100.0}" ) self.assertEqual(account.currency, "CNY") self.assertEqual(account.pre_balance, 10000000.0) self.assertEqual(account.balance, 9998650.0) self.assertEqual(account["commission"], 50.0) self.assertEqual(account["margin"], 4797.200000000001) self.assertEqual(account.position_profit, 0.0) self.assertEqual(account.available, 9989752.8) self.assertNotEqual(account.ctp_balance, account.ctp_balance) # nan self.assertEqual(account.float_profit, -300.0) self.assertEqual(account.position_profit, 0.0) self.assertEqual(account.margin, 4797.200000000001) self.assertEqual(account.commission, 50.0) self.assertEqual(account.premium, -5400.0) self.assertEqual(account.risk_ratio, 0.00047978477094407754) self.assertEqual(account.market_value, 4100.0) api.close()
from tqsdk import TqApi, TqAccount import nest_asyncio nest_asyncio.apply() # api = TqApi(TqAccount("H华安期货", "117889998", "262010",front_broker='6020',front_url='tcp://183.11.217.235:41207'),web_gui="0.0.0.0:9876") # api = TqApi(TqAccount("快期模拟", "cjj208", "Chenjj1230")) api = TqApi(TqAccount("simnow", "090828", "jimc1230", front_broker='9999', front_url='tcp://180.168.146.187:10100'), web_gui="0.0.0.0:9876") # 获得 m2005 的持仓引用,当持仓有变化时 position 中的字段会对应更新 position = api.get_position("SHFE.rb2005") # 获得资金账户引用,当账户有变化时 account 中的字段会对应更新 account = api.get_account() # 下单并返回委托单的引用,当该委托单有变化时 order 中的字段会对应更新 order = api.insert_order(symbol="SHFE.rb2005", direction="BUY", offset="OPEN", volume=2, limit_price=3521) #canorder = api.cancel_order(order) while True: api.wait_update() if api.is_changing(order, ["status", "volume_orign", "volume_left"]): #subprocess.call("cls",shell=True) print("单状态: %s, 已成交: %d 手" % (order.status, order.volume_orign - order.volume_left)) if api.is_changing(position, "pos_long_today"):
class Turtle: def __init__(self, account, symbol, donchian_channel_open_position=20, donchian_channel_stop_profit=10, atr_day_length=20, max_risk_ratio=0.5): self.account = account # 交易账号 self.symbol = symbol # 合约代码 self.donchian_channel_open_position = donchian_channel_open_position # 唐奇安通道的天数周期(开仓) self.donchian_channel_stop_profit = donchian_channel_stop_profit # 唐奇安通道的天数周期(止盈) self.atr_day_length = atr_day_length # ATR计算所用天数 self.max_risk_ratio = max_risk_ratio # 最高风险度 self.state = { "position": 0, # 本策略净持仓数(正数表示多头,负数表示空头,0表示空仓) "last_price": float("nan"), # 上次调仓价 } self.n = 0 # 平均真实波幅(N值) self.unit = 0 # 买卖单位 self.donchian_channel_high = 0 # 唐奇安通道上轨 self.donchian_channel_low = 0 # 唐奇安通道下轨 self.api = TqApi(self.account) self.quote = self.api.get_quote(self.symbol) # 由于ATR是路径依赖函数,因此使用更长的数据序列进行计算以便使其值稳定下来 kline_length = max(donchian_channel_open_position + 1, donchian_channel_stop_profit + 1, atr_day_length * 5) self.klines = self.api.get_kline_serial(self.symbol, 24 * 60 * 60, data_length=kline_length) self.account = self.api.get_account() self.target_pos = TargetPosTask(self.api, self.symbol, init_pos=self.state["position"]) def recalc_paramter(self): # 平均真实波幅(N值) self.n = ATR(self.klines, self.atr_day_length)["atr"].iloc[-1] # 买卖单位 self.unit = int((self.account.balance * 0.01) / (self.quote.volume_multiple * self.n)) # 唐奇安通道上轨:前N个交易日的最高价 self.donchian_channel_high = max( self.klines.high[-self.donchian_channel_open_position - 1:-1]) # 唐奇安通道下轨:前N个交易日的最低价 self.donchian_channel_low = min( self.klines.low[-self.donchian_channel_open_position - 1:-1]) print("唐其安通道上下轨: %f, %f" % (self.donchian_channel_high, self.donchian_channel_low)) return True def set_position(self, pos): self.state["position"] = pos self.state["last_price"] = self.quote["last_price"] self.target_pos.set_target_volume(self.state["position"]) def try_open(self): """开仓策略""" while self.state["position"] == 0: self.api.wait_update() if self.api.is_changing(self.klines.iloc[-1], "datetime"): # 如果产生新k线,则重新计算唐奇安通道及买卖单位 self.recalc_paramter() if self.api.is_changing(self.quote, "last_price"): print("最新价: %f" % self.quote.last_price) if self.quote.last_price > self.donchian_channel_high: # 当前价>唐奇安通道上轨,买入1个Unit;(持多仓) print("当前价>唐奇安通道上轨,买入1个Unit(持多仓): %d 手" % self.unit) self.set_position(self.state["position"] + self.unit) elif self.quote.last_price < self.donchian_channel_low: # 当前价<唐奇安通道下轨,卖出1个Unit;(持空仓) print("当前价<唐奇安通道下轨,卖出1个Unit(持空仓): %d 手" % self.unit) self.set_position(self.state["position"] - self.unit) def try_close(self): """交易策略""" while self.state["position"] != 0: self.api.wait_update() if self.api.is_changing(self.quote, "last_price"): print("最新价: ", self.quote.last_price) if self.state["position"] > 0: # 持多单 # 加仓策略: 如果是多仓且行情最新价在上一次建仓(或者加仓)的基础上又上涨了0.5N,就再加一个Unit的多仓,并且风险度在设定范围内(以防爆仓) if self.quote.last_price >= self.state[ "last_price"] + 0.5 * self.n and self.account.risk_ratio <= self.max_risk_ratio: print("加仓:加1个Unit的多仓") self.set_position(self.state["position"] + self.unit) # 止损策略: 如果是多仓且行情最新价在上一次建仓(或者加仓)的基础上又下跌了2N,就卖出全部头寸止损 elif self.quote.last_price <= self.state[ "last_price"] - 2 * self.n: print("止损:卖出全部头寸") self.set_position(0) # 止盈策略: 如果是多仓且行情最新价跌破了10日唐奇安通道的下轨,就清空所有头寸结束策略,离场 if self.quote.last_price <= min( self.klines. low[-self.donchian_channel_stop_profit - 1:-1]): print("止盈:清空所有头寸结束策略,离场") self.set_position(0) elif self.state["position"] < 0: # 持空单 # 加仓策略: 如果是空仓且行情最新价在上一次建仓(或者加仓)的基础上又下跌了0.5N,就再加一个Unit的空仓,并且风险度在设定范围内(以防爆仓) if self.quote.last_price <= self.state[ "last_price"] - 0.5 * self.n and self.account.risk_ratio <= self.max_risk_ratio: print("加仓:加1个Unit的空仓") self.set_position(self.state["position"] - self.unit) # 止损策略: 如果是空仓且行情最新价在上一次建仓(或者加仓)的基础上又上涨了2N,就平仓止损 elif self.quote.last_price >= self.state[ "last_price"] + 2 * self.n: print("止损:卖出全部头寸") self.set_position(0) # 止盈策略: 如果是空仓且行情最新价升破了10日唐奇安通道的上轨,就清空所有头寸结束策略,离场 if self.quote.last_price >= max( self.klines. high[-self.donchian_channel_stop_profit - 1:-1]): print("止盈:清空所有头寸结束策略,离场") self.set_position(0) def strategy(self): """海龟策略""" print("等待K线及账户数据...") deadline = time.time() + 5 while not self.recalc_paramter(): if not self.api.wait_update(deadline=deadline): raise Exception("获取数据失败,请确认行情连接正常并已经登录交易账户") while True: self.try_open() self.try_close()
data_length = 200 # k线数据长度 SYMBOL = "SHFE.rb2005" # 合约代码 api = TqApi(TqAccount("simnow", "090828", "jimc1230",front_broker='9999',front_url='tcp://180.168.146.187:10100'),web_gui="0.0.0.0:9876")#web_gui="0.0.0.0:9876" # api = TqApi(backtest=TqBacktest(start_dt=date(2020, 3,10), end_dt=date(2020, 3, 19)),web_gui="0.0.0.0:9876")#"0.0.0.0:9876"#回测模式 # api = TqApi(backtest = TqReplay(date(2020,3,18)),web_gui="0.0.0.0:9876")#复盘模式 print("策略开始运行") # "duration_seconds=60"为一分钟线, 日线的duration_seconds参数为: 24*60*60 klines = api.get_kline_serial(SYMBOL, duration_seconds=1*60, data_length=data_length) #收盘后不可查 target_pos = TargetPosTask(api, SYMBOL) position = api.get_position(SYMBOL)#指定一个品种查看持仓相关信息 account = api.get_account()#获取用户账户资金信息 while True: api.wait_update() if api.is_changing(klines.iloc[-1], "datetime"): # 产生新k线:重新计算SMA klines["ma5"]=ma(klines["close"], 5) klines["ma10"]=ma(klines["close"], 10) klines["ma89"]=ma(klines["close"], 89) klines["ma144"]=ma(klines["close"], 144) sar=SAR(klines, 4, 0.02, 0.2) if api.is_changing(klines.iloc[-1], "datetime"): # 产生新k线:重新计算SMA if klines['close'].iloc[-1] < klines['ma89'].iloc[-2]:
def run_tianqin_code(bid, user_id, pwd, td_url): api = TqApi(TqAccount(bid, user_id, pwd), auth="[email protected],MaYanQiong", _stock=True, _md_url="wss://nfmd.shinnytech.com/t/nfmd/front/mobile", _td_url=td_url) print(api._md_url) is_ctp = False if bid == "快期模拟" else True account = api.get_account() if bid == "快期模拟": assert account.ctp_balance == '-' or math.isnan(account.ctp_balance) assert account.ctp_available == '-' or math.isnan(account.ctp_available) else: logger.info(f"{account.ctp_balance}, {account.ctp_available}") logger.info(f"{'='*30} 登录成功后,账户初始状态 {'='*30}") positions = api._data["trade"][user_id]["positions"] orders = api._data["trade"][user_id]["orders"] check_orders(orders, api, is_ctp) check_positions(positions, api, is_ctp) check_account(account, positions, is_ctp) logger.info(f"{'='*12} 期权 开仓 {'='*12}") quote = api.get_quote("CZCE.RM105") # ETF 期权 print(quote) # 挂单 # order = api.insert_order(symbol="SSE.10002513", direction="BUY", offset="OPEN", limit_price=quote.lower_limit + quote.price_tick, volume=2) # 可成交 order = api.insert_order(symbol="CZCE.RM105", direction="BUY", offset="OPEN", limit_price=quote.ask_price1, volume=1) # order = api.insert_order(symbol="SSE.10002513", direction="BUY", offset="OPEN", limit_price=quote.ask_price1, volume=3) # 可成交 FAK 下单失败,CTP:交易所不支持的价格类型 # order = api.insert_order(symbol="SSE.10002513", direction="BUY", offset="OPEN", limit_price=quote.ask_price1, volume=2, advanced="FAK") # 可成交 FOK # order = api.insert_order(symbol="SSE.10002513", direction="BUY", offset="OPEN", limit_price=quote.ask_price1, volume=2, advanced="FOK") # BEST # order = api.insert_order(symbol="SSE.10002513", direction="SELL", offset="CLOSE", limit_price="BEST", volume=10) # BEST FOK 下单失败,已撤单报单被拒绝12038,合约代码:SSE.10002513,下单方向:买,开平标志:开仓,委托价格:最优价,委托手数:3 # order = api.insert_order(symbol="SSE.10002513", direction="SELL", offset="CLOSE", limit_price="BEST", volume=3, advanced="FOK") # any_price 通知: 下单失败,CTP:交易所不支持的价格类型 # order = api.insert_order(symbol="SSE.10002513", direction="BUY", offset="OPEN", volume=3) # FIVELEVEL 通知: 下单失败,CTP:交易所不支持的价格类型 # order = api.insert_order(symbol="SSE.10002513", direction="BUY", offset="OPEN", limit_price="FIVELEVEL", volume=3) while order.status == "ALIVE": api.wait_update() api.wait_update() api.wait_update() check_all(api, bid, user_id) # logger.info(f"{'='*30} 发平仓挂单 {'='*30}") # positions = api._data["trade"][user_id]["positions"] # for pos in positions.values(): # symbol = f"{pos.exchange_id}.{pos.instrument_id}" # quote = api.get_quote(symbol) # if pos.pos_long > 0: # api.insert_order(symbol=symbol, direction="SELL", offset="CLOSE", # limit_price=quote.upper_limit - quote.price_tick, # volume=pos.pos_long) # if pos.pos_short > 0: # api.insert_order(symbol=symbol, direction="BUY", offset="CLOSE", # limit_price=quote.lower_limit + quote.price_tick, # volume=pos.pos_short) # check_all(api, bid, user_id) api.close()
def double_moving_average(api: TqApi, symbol: str, max_position: int = 10, fast: int = 5, slow: int = 20): strategy_name: str = 'DoubleMovingAverage' api: TqApi = api symbol: str = symbol timeout: int = 5 max_position: int = max_position fast: int = fast slow: int = slow ma: DataFrame = DataFrame() tq_account: Account = api.get_account() tq_position: Position = api.get_position(symbol) tq_candlestick: DataFrame = api.get_kline_serial(symbol=symbol, duration_seconds=24 * 60 * 60) tq_target_pos = TargetPosTask(api, symbol) deadline: float try: while True: deadline = time.time() + timeout if not api.wait_update(deadline=deadline): raise RuntimeError('没有在规定时间内获得数据!') # api.wait_update() if api.is_changing(tq_candlestick): ma['fast'] = tafunc.ma(tq_candlestick.close, fast) ma['slow'] = tafunc.ma(tq_candlestick.close, slow) tq_candlestick['ma_fast'] = ma['fast'] tq_candlestick['ma_fast.color'] = 'green' tq_candlestick['ma_slow'] = ma['slow'] tq_candlestick['ma_slow.color'] = 0xFF9933CC # 最新的快均线数值 > 最新的慢均线数值,且 前一根快均线数值 < 前一根慢均线数值 # 即快均线从下向上穿过慢均线 if (ma['fast'].iloc[-1] > ma['slow'].iloc[-1] and ma['fast'].iloc[-2] < ma['slow'].iloc[-2]): # # 如果有空仓,平空仓 # if tq_position.pos_short > 0: # api.insert_order(symbol=symbol, # direction='BUY', # offset='CLOSE', # limit_price=tq_candlestick.close.iloc[-1], # volume=tq_position.pos_short # ) # # 开多仓 # api.insert_order(symbol=symbol, # direction='BUY', # offset='OPEN', # limit_price=tq_candlestick.close.iloc[-1], # volume=max_position # ) tq_target_pos.set_target_volume(max_position) # 最新的快均线数值 < 最新的慢均线数值,且 前一根快均线数值 > 前一根慢均线数值 # 即快均线从上向下穿过慢均线 if (ma['fast'].iloc[-1] < ma['slow'].iloc[-1] and ma['fast'].iloc[-2] > ma['slow'].iloc[-2]): # # 如果有多仓,平多仓 # if tq_position.pos_short > 0: # api.insert_order(symbol=symbol, # direction='SELL', # offset='CLOSE', # limit_price=tq_candlestick.close.iloc[-1], # volume=tq_position.pos_short # ) # # 开空仓 # api.insert_order(symbol=symbol, # direction='SELL', # offset='OPEN', # limit_price=tq_candlestick.close.iloc[-1], # volume=max_position # ) tq_target_pos.set_target_volume(-max_position) except BacktestFinished: api.close() print(f'参数: fast={fast}, slow={slow}, 最终权益={tq_account["balance"]}')
class Turtle: def __init__(self, account_id, symbol, donchian_channel_open_position=20, donchian_channel_stop_profit=10, atr_day_length=20): self.account_id = account_id self.symbol = symbol # 合约代码 self.donchian_channel_open_position = donchian_channel_open_position # 唐奇安通道的天数周期(开仓) self.donchian_channel_stop_profit = donchian_channel_stop_profit # 唐奇安通道的天数周期(止盈) self.atr_day_length = atr_day_length # ATR计算所用天数 self.state = { "position": 0, # 本策略净持仓数(正数表示多头,负数表示空头,0表示空仓) "last_price": float("nan"), # 上次调仓价 } self.n = 0 self.unit = 0 self.donchian_channel_high = 0 self.donchian_channel_low = 0 self.api = TqApi(self.account_id) self.quote = self.api.get_quote(self.symbol) # 由于ATR是路径依赖函数,因此使用更长的数据序列进行计算以便使其值稳定下来 kline_length = max(donchian_channel_open_position + 1, donchian_channel_stop_profit + 1, atr_day_length * 5) self.klines = self.api.get_kline_serial(self.symbol, 24 * 60 * 60, data_length=kline_length) self.account = self.api.get_account() self.target_pos = TargetPosTask(self.api, self.symbol, init_pos=self.state["position"]) def recalc_paramter(self): try: df = self.klines.to_dataframe() # 本交易日的平均真实波幅(N值) self.n = talib.ATR(df["high"], df["low"], df["close"], timeperiod=self.atr_day_length).iloc[-1] # 买卖单位 self.unit = int((self.account["balance"] * 0.01) / (self.quote["volume_multiple"] * self.n)) print('atr:', self.n, " unit:", self.unit) # 唐奇安通道上轨:前N个交易日的最高价 self.donchian_channel_high = max(self.klines.high[-self.donchian_channel_open_position - 1:-1]) # 唐奇安通道下轨:前N个交易日的最低价 self.donchian_channel_low = min(self.klines.low[-self.donchian_channel_open_position - 1:-1]) print("唐其安通道上下轨:", self.donchian_channel_high, self.donchian_channel_low) except Exception: # 若尚未接收到数据, 即数据为NaN, 则在ATR或unit计算时会报错 return False return True def set_position(self, pos): self.state["position"] = pos self.state["last_price"] = self.quote["last_price"] self.target_pos.set_target_volume(self.state["position"]) def try_open(self): """开仓策略""" while self.state["position"] == 0: self.api.wait_update() if self.api.is_changing(self.klines[-1], "datetime"): # 如果产生新k线,则重新计算唐奇安通道及买卖单位 self.recalc_paramter() if self.api.is_changing(self.quote, "last_price"): print("最新价: ", self.quote["last_price"]) if self.quote["last_price"] > self.donchian_channel_high: # 当前价>唐奇安通道上轨,买入1个Unit;(持多仓) print("当前价>唐奇安通道上轨,买入1个Unit(持多仓):", self.unit, "手") self.set_position(self.state["position"] + self.unit) elif self.quote["last_price"] < self.donchian_channel_low: # 当前价<唐奇安通道下轨,卖出1个Unit;(持空仓) print("当前价<唐奇安通道下轨,卖出1个Unit(持空仓):", self.unit, "手") self.set_position(self.state["position"] - self.unit) def try_close(self): """交易策略""" while self.state["position"] != 0: self.api.wait_update() if self.api.is_changing(self.quote, "last_price"): print("最新价: ", self.quote["last_price"]) if self.state["position"] > 0: # 持多单 # 加仓策略: 如果是多仓且资产的价格在上一次建仓(或者加仓)的基础上又上涨了0.5N,就再加一个Unit的多仓 if self.quote["last_price"] >= self.state["last_price"] + 0.5 * self.n: print("加仓:加1个Unit的多仓") self.set_position(self.state["position"] + self.unit) # 止损策略: 如果是多仓且资产的价格在上一次建仓(或者加仓)的基础上又下跌了2N,就卖出全部头寸止损 elif self.quote["last_price"] <= self.state["last_price"] - 2 * self.n: print("止损:卖出全部头寸") self.set_position(0) # 止盈策略: 如果是多仓且当前资产价格跌破了10日唐奇安通道的下轨,就清空所有头寸结束策略,离场 if self.quote["last_price"] <= min(self.klines.low[-self.donchian_channel_stop_profit - 1:-1]): print("止盈:清空所有头寸结束策略,离场") self.set_position(0) elif self.state["position"] < 0: # 持空单 # 加仓策略: 如果是空仓且资产的价格在上一次建仓(或者加仓)的基础上又下跌了0.5N,就再加一个Unit的空仓 if self.quote["last_price"] <= self.state["last_price"] - 0.5 * self.n: print("加仓:加1个Unit的空仓") self.set_position(self.state["position"] - self.unit) # 止损策略: 如果是空仓且资产的价格在上一次建仓(或者加仓)的基础上又上涨了2N,就平仓止损 elif self.quote["last_price"] >= self.state["last_price"] + 2 * self.n: print("止损:卖出全部头寸") self.set_position(0) # 止盈策略: 如果是空仓且当前资产价格升破了10日唐奇安通道的上轨,就清空所有头寸结束策略,离场 if self.quote["last_price"] >= max(self.klines.high[-self.donchian_channel_stop_profit - 1:-1]): print("止盈:清空所有头寸结束策略,离场") self.set_position(0) def strategy(self): """海龟策略""" print("等待K线及账户数据...") deadline = time.time()+5 while not self.recalc_paramter(): if not self.api.wait_update(deadline=deadline): raise Exception("获取数据失败,请确认行情连接正常并已经登录交易账户") while True: self.try_open() self.try_close()
def run_tianqin_code(bid, user_id, pwd, td_url): api = TqApi(TqAccount(bid, user_id, pwd), auth="[email protected],MaYanQiong", _td_url=td_url) is_ctp = False if bid == "快期模拟" else True account = api.get_account() if bid == "快期模拟": assert account.ctp_balance == '-' or math.isnan(account.ctp_balance) assert account.ctp_available == '-' or math.isnan( account.ctp_available) else: logger.info(f"{account.ctp_balance}, {account.ctp_available}") logger.info(f"{'='*30} 登录成功后,账户初始状态 {'='*30}") positions = api._data["trade"][user_id]["positions"] orders = api._data["trade"][user_id]["orders"] check_orders(orders, api, is_ctp) check_positions(positions, api, is_ctp) check_account(account, positions, is_ctp) logger.info(f"{'='*30} 全部撤单 & 全部平仓 {'='*30}") for order in orders.values(): if order.status != "FINISHED": api.cancel_order(order) for pos in positions.values(): symbol = f"{pos.exchange_id}.{pos.instrument_id}" quote = api.get_quote(symbol) if pos.pos_long > 0: api.insert_order(symbol=symbol, direction="SELL", offset="CLOSE", limit_price=quote.bid_price1, volume=pos.pos_long) if pos.pos_short > 0: api.insert_order(symbol=symbol, direction="BUY", offset="CLOSE", limit_price=quote.ask_price1, volume=pos.pos_short) while True: api.wait_update(deadline=time.time() + 30) # 全部持仓清 0 is_all_clear = True for pos in positions.values(): if pos.pos_long > 0 or pos.pos_short > 0: is_all_clear = False for order in orders.values(): if order.status != "FINISHED": is_all_clear = False if is_all_clear: logger.info("全部撤单 & 全部平仓 ok") break else: logger.info("还没完成全部撤单 & 全部平仓") logger.info(f"{'='*12} 期货 开仓 {'='*12}") quote = api.get_quote("CZCE.RM105") api.insert_order(symbol="CZCE.RM105", direction="BUY", offset="OPEN", limit_price=quote.lower_limit + quote.price_tick, volume=2) api.insert_order(symbol="CZCE.RM105", direction="BUY", offset="OPEN", limit_price=quote.ask_price1, volume=3) quote1 = api.get_quote("CZCE.CF105") api.insert_order(symbol="CZCE.CF105", direction="SELL", offset="OPEN", limit_price=quote1.upper_limit - quote1.price_tick, volume=2) api.insert_order(symbol="CZCE.CF105", direction="SELL", offset="OPEN", limit_price=quote1.bid_price1, volume=3) check_all(api, bid, user_id) # logger.info(f"{'='*12} 期权 开仓 {'='*12}") # quote = api.get_quote("CZCE.RM009C2300") # api.insert_order(symbol="CZCE.RM009C2300", direction="BUY", offset="OPEN", # limit_price=quote.lower_limit + quote.price_tick, # volume=2) # api.insert_order(symbol="CZCE.RM009C2300", direction="BUY", offset="OPEN", limit_price=quote.ask_price1, # volume=3) # quote1 = api.get_quote("CZCE.CF009C11600") # api.insert_order(symbol="CZCE.CF009C11600", direction="SELL", offset="OPEN", # limit_price=quote1.upper_limit - quote1.price_tick, # volume=2) # api.insert_order(symbol="CZCE.CF009C11600", direction="SELL", offset="OPEN", limit_price=quote1.bid_price1, # volume=3) # # quote2 = api.get_quote("CZCE.RM009P2300") # api.insert_order(symbol="CZCE.RM009P2300", direction="BUY", offset="OPEN", # limit_price=quote2.lower_limit + quote2.price_tick, # volume=2) # api.insert_order(symbol="CZCE.RM009P2300", direction="BUY", offset="OPEN", limit_price=quote2.ask_price1, # volume=3) # quote3 = api.get_quote("CZCE.CF009C11600") # api.insert_order(symbol="CZCE.CF009P11600", direction="SELL", offset="OPEN", # limit_price=quote3.upper_limit - quote3.price_tick, # volume=2) # api.insert_order(symbol="CZCE.CF009P11600", direction="SELL", offset="OPEN", limit_price=quote3.bid_price1, # volume=3) # PUT # check_all(api, bid, user_id) # logger.info(f"{'='*30} 发平仓挂单 {'='*30}") # positions = api._data["trade"][user_id]["positions"] # for pos in positions.values(): # symbol = f"{pos.exchange_id}.{pos.instrument_id}" # quote = api.get_quote(symbol) # if pos.pos_long > 0: # api.insert_order(symbol=symbol, direction="SELL", offset="CLOSE", # limit_price=quote.upper_limit - quote.price_tick, # volume=pos.pos_long) # if pos.pos_short > 0: # api.insert_order(symbol=symbol, direction="BUY", offset="CLOSE", # limit_price=quote.lower_limit + quote.price_tick, # volume=pos.pos_short) # check_all(api, bid, user_id) api.close()
import logging logging.basicConfig(filename='log.txt',filemode='a',level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s') #logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s') #pdb.set_trace() print('This is yhlz\'s trading server,now started!\n') try: #api=TqApi(TqAccount('快期模拟','284837','86888196')) api=TqApi(TqAccount('simnow','133492','Yhlz0000')) logging.info('success sign in! with simnow') # api=TqApi(TqAccount('H华安期货','100909186','Yhlz0000')) # logging.info('success sign in! with 100909186') except Exception: logging.info('problem with sign in!') raise SystemExit contral='' #use for contral the whole program stop or not ,if it equal to 'q' then progam stoped account=api.get_account() #account is a value is a object can used as account.balence etc. position=api.get_position() #position is a dict where the key is contract,value is each contract's features class Get_Input(threading.Thread): # this thread contral wheather to stop whole program def run(self): global contral while True: contral=input('press q to quit!') logging.info(contral) logging.info(time.ctime()) now=time.localtime(time.time()) if now.tm_hour==15 or now.tm_hour==3 or contral=='q': logging.info('Ready to quit') return #######---------------------------get all data and all strategy needed ready-------------------------------------####### f=open(r'strategytorun.txt') strategy_list=f.readlines() #a list of strategy need to run