예제 #1
0
class Strategy:

    def __init__(self, instrument_id, time_frame, fast_length, slow_length, long_stop, short_stop, start_asset):
        try:
            print("{} {} 双均线多空策略已启动!".format(get_localtime(), instrument_id))   # 程序启动时打印提示信息
            config.loads('config.json')  # 载入配置文件
            self.instrument_id = instrument_id  # 合约ID
            self.time_frame = time_frame  # k线周期
            self.exchange = OKEXFUTURES(config.access_key, config.secret_key, config.passphrase, self.instrument_id)  # 初始化交易所
            self.position = POSITION(self.exchange, self.instrument_id, self.time_frame)  # 初始化potion
            self.market = MARKET(self.exchange, self.instrument_id, self.time_frame)  # 初始化market
            self.indicators = INDICATORS(self.exchange, self.instrument_id, self.time_frame)    # 初始化indicators
            # 在第一次运行程序时,将初始资金数据保存至数据库中
            self.database = "回测"    # 回测时必须为"回测"
            self.datasheet = self.instrument_id.split("-")[0].lower() + "_" + time_frame
            if config.first_run == "true":
                storage.mysql_save_strategy_run_info(self.database, self.datasheet, get_localtime(),
                                                "none", 0, 0, 0, 0, "none", 0, 0, 0, start_asset)
            # 读取数据库中保存的总资金数据
            self.total_asset = storage.read_mysql_datas(0, self.database, self.datasheet, "总资金", ">")[-1][-1]
            self.total_profit = storage.read_mysql_datas(0, self.database, self.datasheet, "总资金", ">")[-1][-2]  # 策略总盈亏
            self.counter = 0  # 计数器
            self.fast_length = fast_length  # 短周期均线长度
            self.slow_length = slow_length  # 长周期均线长度
            self.long_stop = long_stop   # 多单止损幅度
            self.short_stop = short_stop    # 空单止损幅度
            self.contract_value = self.market.contract_value()  # 合约面值,每次获取需发起网络请求,故于此处声明变量,优化性能
        except:
            logger.warning()

    def begin_trade(self, kline=None):
        try:
            if self.indicators.CurrentBar(kline=kline) < self.slow_length:  # 如果k线数据不够长就返回
                return
            timestamp = ts_to_datetime_str(utctime_str_to_ts(kline[-1][0])) if kline else get_localtime()    # 非回测模式下时间戳就是当前本地时间
            # 计算策略信号
            ma = self.indicators.MA(self.fast_length, self.slow_length, kline=kline)
            fast_ma = ma[0]
            slow_ma = ma[1]
            cross_over = fast_ma[-2] >= slow_ma[-2] and fast_ma[-3] < slow_ma[-3]   # 不用当根k线上的ma来计算信号,防止信号闪烁
            cross_below = slow_ma[-2] >= fast_ma[-2] and slow_ma[-3] < fast_ma[-3]
            if self.indicators.BarUpdate(kline=kline):     # 如果k线更新,计数器归零
                self.counter = 0
            if self.counter < 1:
                # 按照策略信号开平仓
                if cross_over:     # 金叉时
                    if self.position.amount() == 0:     # 若当前无持仓,则买入开多并推送下单结果
                        price = self.market.open(-1, kline=kline)  # 下单价格=此根k线收盘价
                        amount = round(self.total_asset / self.contract_value)   # 数量=总资金/价格/合约面值
                        info = self.exchange.buy(price, amount)
                        push(info)
                        storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "买入开多",
                                                        price, amount, amount * self.contract_value, price,
                                                        "long", amount, 0, self.total_profit, self.total_asset)     # 将信息保存至数据库
                    if self.position.direction() == 'short':    # 若当前持空头,先平空再开多
                        profit = self.position.covershort_profit(market_type="usd_contract", last=self.market.open(-1, kline=kline))  # 在平空前先计算逻辑盈亏,当前最新成交价为开盘价
                        self.total_profit += profit
                        self.total_asset += profit  # 计算此次盈亏后的总资金
                        cover_short_price = self.market.open(-1, kline=kline)
                        cover_short_amount = self.position.amount()
                        open_long_price = self.market.open(-1, kline=kline)
                        open_long_amount = round(self.total_asset / self.contract_value)
                        info = self.exchange.BUY(cover_short_price, cover_short_amount, open_long_price, open_long_amount)
                        push("此次盈亏:{} 当前总资金:{}".format(profit, self.total_asset) + str(info))   # 需将返回的下单结果info转换为字符串后进行拼接
                        storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "平空开多",
                                                        open_long_price, open_long_amount, open_long_amount * self.contract_value,
                                                        open_long_price, "long", open_long_amount, profit, self.total_profit, self.total_asset)
                if cross_below:     # 死叉时
                    if self.position.amount() == 0:
                        price = self.market.open(-1, kline=kline)
                        amount = round(self.total_asset / self.contract_value)
                        info = self.exchange.sellshort(price, amount)
                        push(info)
                        storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "卖出开空",
                                                    price, amount, amount * self.contract_value, price,
                                                    "short", amount, 0, self.total_profit, self.total_asset)
                    if self.position.direction() == 'long':
                        profit = self.position.coverlong_profit(market_type="usd_contract", last=self.market.open(-1, kline=kline))     # 在平多前先计算逻辑盈亏,当前最新成交价为开盘价
                        self.total_profit += profit
                        self.total_asset += profit
                        cover_long_price = self.market.open(-1, kline=kline)
                        cover_long_amount = self.position.amount()
                        open_short_price = self.market.open(-1, kline=kline)
                        open_short_amount = round(self.total_asset / self.contract_value)
                        info = self.exchange.SELL(cover_long_price,
                                                  cover_long_amount,
                                                  open_short_price,
                                                  open_short_amount)
                        push("此次盈亏:{} 当前总资金:{}".format(profit, self.total_asset) + str(info))
                        storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp, "平多开空",
                                                        open_short_price, open_short_amount,
                                                        open_short_amount * self.contract_value,
                                                        open_short_price, "short", open_short_amount, profit, self.total_profit,
                                                        self.total_asset)
                # 止损
                if self.position.amount() > 0:
                    if self.position.direction() == 'long' and self.market.low(-1, kline=kline) <= self.position.price() * self.long_stop:    # 多单止损
                        profit = self.position.coverlong_profit(market_type="usd_contract", last=self.position.price() * self.long_stop)    # 在平多前先计算逻辑盈亏,当前最新成交价为止损价
                        self.total_profit += profit
                        self.total_asset += profit
                        price = self.position.price() * self.long_stop
                        amount = self.position.amount()
                        info = self.exchange.sell(price, amount)
                        push("此次盈亏:{} 当前总资金:{}".format(profit, self.total_asset) + str(info))
                        storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp,
                                                        "卖出止损", price, amount,
                                                        amount * self.contract_value,
                                                        0, "none", 0, profit, self.total_profit,
                                                        self.total_asset)
                        self.counter += 1   # 计数器加1,控制此根k线上不再下单

                    if self.position.direction() == 'short' and self.market.high(-1, kline=kline) >= self.position.price() * self.short_stop:  # 空头止损
                        profit = self.position.covershort_profit(market_type="usd_contract", last=self.position.price() * self.short_stop)
                        self.total_profit += profit
                        self.total_asset += profit
                        price = self.position.price() * self.short_stop
                        amount = self.position.amount()
                        info = self.exchange.buytocover(price, amount)
                        push("此次盈亏:{} 当前总资金:{}".format(profit, self.total_asset) + str(info))
                        storage.mysql_save_strategy_run_info(self.database, self.datasheet, timestamp,
                                                        "买入止损", price, amount,
                                                        amount * self.contract_value,
                                                        0, "none", 0, profit, self.total_profit,
                                                        self.total_asset)
                        self.counter += 1
        except:
            logger.info()
예제 #2
0
class Strategy:
    def __init__(self, instrument_id, time_frame, fast_length, slow_length,
                 long_stop, short_stop, start_asset, precision):
        config.loads('config.json')  # 载入配置文件
        self.instrument_id = instrument_id  # 合约ID
        self.time_frame = time_frame  # k线周期
        self.precision = precision  # 精度,即币对的最小交易数量
        self.exchange = OKEXSPOT(config.access_key, config.secret_key,
                                 config.passphrase,
                                 self.instrument_id)  # 初始化交易所
        self.position = POSITION(self.exchange, self.instrument_id,
                                 self.time_frame)  # 初始化potion
        self.market = MARKET(self.exchange, self.instrument_id,
                             self.time_frame)  # 初始化market
        self.indicators = INDICATORS(self.exchange, self.instrument_id,
                                     self.time_frame)  # 初始化indicators
        # 在第一次运行程序时,将初始资金数据保存至数据库中
        self.database = "回测"  # 回测时必须为"回测"
        self.datasheet = self.instrument_id.split(
            "-")[0].lower() + "_" + time_frame
        if config.first_run:
            storage.mysql_save_strategy_run_info(self.database, self.datasheet,
                                                 get_localtime(), "none", 0, 0,
                                                 0, 0, "none", 0, 0, 0,
                                                 start_asset)
        # 读取数据库中保存的总资金数据
        self.total_asset = storage.read_mysql_datas(0, self.database,
                                                    self.datasheet, "总资金",
                                                    ">")[-1][-1]
        self.total_profit = storage.read_mysql_datas(0, self.database,
                                                     self.datasheet, "总资金",
                                                     ">")[-1][-2]  # 策略总盈亏
        self.counter = 0  # 计数器
        self.fast_length = fast_length  # 短周期均线长度
        self.slow_length = slow_length  # 长周期均线长度
        self.long_stop = long_stop  # 多单止损幅度
        self.short_stop = short_stop  # 空单止损幅度
        self.hold_price = 0  # 注意:okex的现货没有获取持仓均价的接口,故需实盘时需要手动记录入场价格。此种写法对于不同的交易所是通用的。
        # 此种写法,若策略重启,持仓价格会回归0
        print("{} {} 双均线多空策略已启动!".format(get_localtime(),
                                         instrument_id))  # 程序启动时打印提示信息

    def begin_trade(self, kline=None):
        try:
            if self.indicators.CurrentBar(
                    kline=kline) < self.slow_length:  # 如果k线数据不够长就返回
                return
            timestamp = ts_to_datetime_str(utctime_str_to_ts(
                kline[-1]
                [0])) if kline else get_localtime()  # 非回测模式下时间戳就是当前本地时间
            # 计算策略信号
            ma = self.indicators.MA(self.fast_length,
                                    self.slow_length,
                                    kline=kline)
            fast_ma = ma[0]
            slow_ma = ma[1]
            cross_over = fast_ma[-2] >= slow_ma[-2] and fast_ma[-3] < slow_ma[
                -3]  # 不用当根k线上的ma来计算信号,防止信号闪烁
            cross_below = slow_ma[-2] >= fast_ma[-2] and slow_ma[-3] < fast_ma[
                -3]
            if self.indicators.BarUpdate(kline=kline):  # 如果k线更新,计数器归零
                self.counter = 0
            if self.counter < 1:
                # 按照策略信号开平仓
                if cross_over and round(
                        self.position.amount()
                ) < self.precision:  # 金叉时,若当前无持仓,则买入开多并推送下单结果。0.1这个数值根据每个币对的最小交易数量决定
                    price = float(self.market.open(
                        -1, kline=kline))  # 下单价格=此根k线开盘价
                    self.hold_price = price  # 记录开仓价格
                    amount = float(self.total_asset / price)  # 数量=总资金/价格
                    info = self.exchange.buy(price, amount)
                    push(info)
                    storage.mysql_save_strategy_run_info(
                        self.database, self.datasheet, timestamp, "买入开多",
                        price, amount, amount * price, price, "long", amount,
                        0, self.total_profit, self.total_asset)  # 将信息保存至数据库
                if cross_below and round(
                        self.position.amount(), 1
                ) >= self.precision:  # 死叉时,如果当前持多就卖出平多。当前持仓数量根据币对的最小交易数量取小数
                    price = float(self.market.open(-1, kline=kline))
                    amount = float(self.position.amount())
                    profit = (price - self.hold_price) * amount  # 计算逻辑盈亏
                    self.total_profit += profit
                    self.total_asset += profit
                    info = self.exchange.sell(price, amount)
                    push(info)
                    self.hold_price = 0  # 平多后记录持仓价格为0
                    storage.mysql_save_strategy_run_info(
                        self.database, self.datasheet, timestamp, "卖出平多",
                        price, amount, amount * price, 0, "none", 0, profit,
                        self.total_profit, self.total_asset)
                # 如果当前持多且最低价小于等于持仓均价*止损幅度,触发止损,卖出平多止损
                if round(self.position.amount(),
                         1) >= self.precision and self.market.low(
                             -1,
                             kline=kline) <= self.hold_price * self.long_stop:
                    price = float(self.hold_price * self.long_stop)
                    amount = float(self.position.amount())
                    profit = (price - self.hold_price) * amount  # 计算逻辑盈亏
                    self.total_profit += profit
                    self.total_asset += profit
                    info = self.exchange.sell(price, amount)
                    push("此次盈亏:{} 当前总资金:{}".format(profit, self.total_asset) +
                         str(info))
                    self.hold_price = 0  # 平多后记录持仓价格为0
                    storage.mysql_save_strategy_run_info(
                        self.database, self.datasheet, timestamp, "卖出止损",
                        price, amount, amount * price, 0, "none", 0, profit,
                        self.total_profit, self.total_asset)
                    self.counter += 1  # 计数器加1,控制此根k线上不再下单
        except Exception as e:
            logger.info()