GTokenTool全网最好的代币发行工具平台
当前位置:首页 >> 加密百科 >> Python 指南:使用 TradingView 指标创建加密货币交易信号

Python 指南:使用 TradingView 指标创建加密货币交易信号

admin 加密百科 21

在交易中,“信号”是根据一组预先定义的条件触发买入或卖出资产的。与自动执行交易的交易机器人不同,信号允许用户自行决定何时进入、退出或保持交易状态。


在本文中,我们将探讨如何使用 TradingView 和CoinGecko API创建自己的交易信号。我们还将讨论如何设置操作系统通知,以便在信号生成时发送警报。

使用 TradingView 指标创建加密货币交易信号

先决条件

在开始之前,您需要以下工具:

  • Python 3.10+

  • IDE(例如 VS Code)

  • CoinGecko 演示 API 密钥

Demo API 是免费使用的,并且足以满足我们的目的。创建你的 CoinGecko 帐户,前往开发者面板,点击“+添加新密钥”即可生成新的 API 密钥。

步骤 1:创建 Python 环境

创建专用的 Python 环境使我们能够有效地管理依赖项,避免版本冲突,并使我们的项目与其他项目和系统级软件包隔离。这种做法可确保更流畅的开发体验,并增强项目的可维护性。

首先创建一个新目录作为项目的根目录。然后使用终端或命令提示符运行以下命令。

# Create venv
Python -m venv env
# Activate env on macOS/Linux
source env/bin/activate  # For macOS/Linux
# activate env on Windows
env\scripts\activate
接下来,让我们安装项目所需的依赖包。最简单的方法是复制下面提供的需求列表,并将其粘贴到requirements.txt项目根目录下的新文本文件中。 
certifi==2024.8.30
charset-normalizer==3.3.2
colorama==0.4.6
idna==3.10
loguru==0.6.0
notify_py==0.3.43
python-dotenv==1.0.1
requests==2.32.3
TradingView-ta==3.3.0
urllib3==2.2.3
win32-setctime==1.1.0
创建文件后,从项目根目录运行以下命令。

pip install -r requirements.txt

这种方法将确保自动安装所有必要的软件包,省去了单独安装每个软件包的麻烦。

.env接下来,在项目根目录中创建一个文件。打开此文件并将您的 CoinGecko API 密钥存储在其中。以这种方式存储 API 密钥通常更安全,因为它可以将敏感信息隔离在源代码之外,并且更易于跨不同环境管理配置。


CG_API_KEY = "YOUR_COINGECKO_DEMO_API_KEY"
为了保持代码库的整洁有序,我们将代码拆分成更小、更易于管理的部分,每个部分都包含在相应的目录中。为了继续操作,请确保您的本地环境具有以下目录结构:

项目目录结构

您需要创建models、services和utils 目录,以及一个  用于执行逻辑的main.py文件。如果您已经创建并初始化了 Python 环境, 那么 env 文件夹应该已经存在。

第 2 步:加载您的加密 API 密钥 

在utils下创建一个load_env.py文件。这将帮助我们在应用程序需要时轻松安全地访问 CoinGecko API 密钥。

import os
from dotenv import load_dotenv
load_dotenv()
cg_api_key = os.getenv("CG_API_KEY")
通过这种方法,我们可以简单地导入load_env.py文件,并且我们的cg_api_key就可以使用,而无需在应用程序内部对其进行硬编码。

步骤3:创建CoinGecko服务

在将加密资产传递给 TradingView 进行分析之前,我们必须先获取加密货币列表。为此,我们将利用 /coins/markets端点。

此端点返回一个符号对象列表,其中包含指向代币图像的链接,我们将在通知中用到它。在 services 目录中,创建一个名为coingecko_service.py的新文件。在此文件中,我们将定义一个包含构造函数和两个方法的类。

我们使用类是因为它们易于扩展,并且使我们的代码更加整洁和有条理。

import requests
from models.coin_markets import MarketCoin
from models.currencies import Currency
from utils.load_env import *
from typing import List
class CoinGecko:
def __init__(self):
self.root = "https://api.coingecko.com/api/v3"
self.headers = {
"accept": "application/json",
"x-cg-demo-api-key": f"{cg_api_key}",
}
def get_all_coins(self, vs_currency: Currency = Currency.USD) -> List[MarketCoin]:
exclude_symbols = ["usdt", "usdc", "steth"]  # Coins to exclude
request_url = self.root + f"/coins/markets?vs_currency={vs_currency.value}"
response = requests.get(request_url, self.headers).json()
return [
MarketCoin(
id=coin_data["id"], symbol=coin_data["symbol"], image=coin_data["image"]
)
for coin_data in response
if coin_data["symbol"] not in exclude_symbols
]
def get_vs_currencies(self):
request_url = self.root + "/simple/supported_vs_currencies"
return requests.get(request_url, self.headers).json()

在构造函数 ( __init__(self) ) 中,我们将声明self.root和self.headers变量,以便在类方法中轻松访问。请注意,x-cg-demo-api-key由一个 f 字符串组成,该字符串包含我们的 CoinGecko API 密钥。要在构造函数中传递 API 密钥,我们只需从位于utils目录中的load_env.py文件导入所有内容,如下所示:from utils.load_env import 。


在get_all_coins()函数中,我们排除了不想分析的币种。该函数采用硬编码,用于排除 TradingView 中不存在的资产对,但可以扩展至包含您不想为其生成信号的任何币种。


在get_all_coins()的返回对象中,我们将 coin_data 转换为 MarketCoin List 对象,以便使用点符号并启用 IDE 提示。


为此,只需在模型目录中创建一个coin_markets.py文件,如下所示:

from dataclasses import dataclass
@dataclass
class MarketCoin:
id: str
symbol: str
image: str
我们只对id、symbol和image感兴趣,所以我们只映射这些属性。

/coins/markets端点需要将vs_currency参数作为请求 URL 的一部分传递。CoinGecko 还提供了一个用于获取受支持货币的端点:simple/supported_vs_currencies。

CoinGecko API 演示密钥 - 准确可靠的加密数据 API

在这里,我们可以采用快速而简单的方法,简单地将“usd”硬编码为 vs_currency 参数的值,或者调用get_vs_currencies方法并将输出存储在枚举中,如下所示:

将货币值存储在枚举中,让我们可以轻松访问所有支持的 vs_currencies,使用点符号,如下所示:Currency.BTC。它还可以在 IDE 中启用类型提示,这是一个很好的附加好处。

接下来,我们在 models 目录下创建一个currencies.py文件,并将get_vs_currencies()的输出转换 为枚举。您可以使用 ChatGPT 或类似工具自动将此输出转换为 Python 枚举,无需手动操作。

我们只需要调用一次get_vs_currencies()并存储其输出,因此它不是我们正在运行的服务的一部分,但我们可能希望进一步扩展此功能,并在一定时间间隔调用它以确保我们始终拥有所有最新支持的货币。


步骤4:创建TradingView服务

现在让我们在服务目录中创建一个tradingview_service.py文件。

在我们的 TradingView 类中,我们只有一个方法和一个空的构造函数。由于构造函数不需要任何初始化逻辑,我们可以将@staticmethod装饰器应用于retrieve_analysis方法。这样我们就可以直接调用TradingView.retrieve_analysis(),而无需实例化类对象。

from tradingview_ta import TA_Handler, Interval, Analysis
class TradingView:
def __init__(self):
pass
@staticmethod
def retrieve_analysis(symbol: str, exchange: str, interval: Interval) -> Analysis:
return TA_Handler(
symbol=symbol,
exchange=exchange,
screener="crypto",
interval=interval,
timeout=None,
).get_analysis()
该方法返回一个Analysis类型的对象,该对象包含四个关键的 TradingView 分析组件:Summary、Moving Average、Oscillators和Indicators。每个组件都提供不同级别的详细程度,使您可以选择最符合您交易目标的数据。

让我们快速浏览一下每一个。

TradingView 摘要

这是顶级分析对象,通过聚合所有可用 TradingView 指标的信号提供简洁的概述。

{'RECOMMENDATION': 'SELL', 'BUY': 6, 'SELL': 10, 'NEUTRAL': 10}
建议通过评估有多少指标发出买入、卖出或中性信号来总结分析。在本例中,6个指标建议买入,10个指标建议卖出,10个指标保持中性。基于此细分,最终建议为卖出。

这是一种轻松获取资产表现概览的方法,无需深入了解更细微的细节。但是,由于它汇总了所有可用指标,因此您无法控制将哪些具体指标纳入分析。

TradingView 移动平均线和震荡指标

与高级摘要相比,移动平均线和振荡器对象提供了特定指标的更详细分类。

移动平均线对象聚合了来自各种指标(例如 EMA、SMA 和 Ichimoku)的信号以生成建议,而振荡器对象由RSI、MACD和AO等指标组成。 

由于我们可以直接访问每个对象中的实际指标,因此我们可以更好地控制在分析中纳入哪些指标以最终生成信号。唯一的限制是,与顶级摘要一样,我们仍然无法访问指标的绝对值,而只能访问基于 TradingView 对每个信号的解读的总体建议。这意味着您无法微调单个指标的阈值,但您仍然可以根据您认为最相关的特定指标来定制您的分析。

TradingView指标

指标对象通过直接访问各种技术指标的信号和实际值,提供最精细的分析。与摘要、移动平均线或振荡指标对象不同,此数据包含原始指标输出,从而实现更个性化、更精确的分析。

{'Recommend.Other': -0.09090909090909091, 'Recommend.All': 0.02121212121212121, 'Recommend.MA': 0.13333333333333333, 'RSI': 49.24379728743299, 'RSI[1]': 46.11115918203463, 'Stoch.K': 30.00241545893786, 'Stoch.D': 24.828502415459596, 'Stoch.K[1]': 30.02603110067388, 'Stoch.D[1]': 20.947485752282283, 'CCI20': -34.64895669097604, 'CCI20[1]': -91.45320627441559, 'ADX': 11.319788699660476, 'ADX+DI': 20.5713442485876, 'ADX-DI': 24.999699186359514, 'ADX+DI[1]': 18.742970807811993, 'ADX-DI[1]': 25.70387666020197, 'AO': -163.44849999998405, 'AO[1]': -182.27894117645337, 'Mom': -231.95999999999185, 'Mom[1]': -115.11000000000058, 'MACD.macd': -30.226527342922054, 'MACD.signal': -14.471741239235282, 'Rec.Stoch.RSI': 0, 'Stoch.RSI.K': 37.11560796682097, 'Rec.WR': 0, 'W.R': -62.14855072463726, 'Rec.BBPower': 1, 'BBPower': -51.33534064942796, 'Rec.UO': 0, 'UO': 48.344956849675896, 'close': 65640.94, 'EMA5': 65598.30866110191, 'SMA5': 65565.95200000002, 'EMA10': 65619.08186587603, 'SMA10': 65630.56700000007, 'EMA20': 65653.53302863668, 'SMA20': 65666.49399999999, 'EMA30': 65653.28441258015, 'SMA30': 65673.201, 'EMA50': 65551.51029171057, 'SMA50': 65757.833, 'EMA100': 65111.13977517033, 'SMA100': 65005.211399999986, 'EMA200': 64182.90234654909, 'SMA200': 64188.96925000001, 'Rec.Ichimoku': 0, 'Ichimoku.BLine': 65703.115, 'Rec.VWMA': -1, 'VWMA': 65664.93179228147, 'Rec.HullMA9': 1, 'HullMA9': 65571.92503703706, 'Pivot.M.Classic.S3': 48455.08666666668, 'Pivot.M.Classic.S2': 55095.106666666674, 'Pivot.M.Classic.S1': 59336.93333333334, 'Pivot.M.Classic.Middle': 61735.12666666667, 'Pivot.M.Classic.R1': 65976.95333333334, 'Pivot.M.Classic.R2': 68375.14666666667, 'Pivot.M.Classic.R3': 75015.16666666666, 'Pivot.M.Fibonacci.S3': 55095.106666666674, 'Pivot.M.Fibonacci.S2': 57631.59430666667, 'Pivot.M.Fibonacci.S1': 59198.63902666667, 'Pivot.M.Fibonacci.Middle': 61735.12666666667, 'Pivot.M.Fibonacci.R1': 64271.61430666667, 'Pivot.M.Fibonacci.R2': 65838.65902666668, 'Pivot.M.Fibonacci.R3': 68375.14666666667, 'Pivot.M.Camarilla.S3': 61752.7545, 'Pivot.M.Camarilla.S2': 62361.423, 'Pivot.M.Camarilla.S1': 62970.0915, 'Pivot.M.Camarilla.Middle': 61735.12666666667, 'Pivot.M.Camarilla.R1': 64187.4285, 'Pivot.M.Camarilla.R2': 64796.097, 'Pivot.M.Camarilla.R3': 65404.7655, 'Pivot.M.Woodie.S3': 53618.73000000001, 'Pivot.M.Woodie.S2': 55556.01500000001, 'Pivot.M.Woodie.S1': 60258.75000000001, 'Pivot.M.Woodie.Middle': 62196.035, 'Pivot.M.Woodie.R1': 66898.77, 'Pivot.M.Woodie.R2': 68836.055, 'Pivot.M.Woodie.R3': 73538.79000000001, 'Pivot.M.Demark.S1': 60536.030000000006, 'Pivot.M.Demark.Middle': 62334.675, 'Pivot.M.Demark.R1': 67176.05, 'open': 65572, 'P.SAR': 65840.55812327839, 'BB.lower': 65438.225523774825, 'BB.upper': 65894.76247622515, 'AO[2]': -169.0890294117562, 'volume': 104.80005, 'change': 0.10515160512895382, 'low': 65571.99, 'high': 65640.94}

这种详细程度可以让您更好地掌控分析。您可以根据特定条件(例如 RSI 突破特定阈值或 MACD 信号线交叉)做出交易决策。但是,您必须自行解读原始指标值,因为 TradingView 不会立即提供买入/卖出建议——它仅提供原始数据。


虽然这提供了最大的灵活性,但也需要对技术分析有更深入的了解。


为了进行分析,我们将利用 TradingView 提供的振荡器和移动平均线对象。在将所有内容整合在一起之前,还有一个步骤,那就是构建通知服务。

步骤 5:创建通知服务

在此步骤中,我们将使用notifypy库设置通知服务,该库使我们能够轻松发送操作系统通知。这对于在代币发出买入信号时提醒我们自己特别有用。

通知服务的实现如下:

from notifypy import Notify
class Notification:
def __init__(self) -> None:
pass
@staticmethod
def send(title: str, text: str, icon: str):
notification = Notify()
notification.title = title
notification.icon = icon
notification.message = text
notification.send()
和以前一样,我们使用@staticmethod装饰器,因此我们可以在代码库中的任何位置简单地调用Notification.send(...) 。

send 方法接受 3 个参数:title、text 和 icon。我们希望通知显示相应币种的图标,因此需要使用get_all_coins()方法返回的 icon 属性。

为了显示通知图标,我们需要从 CoinGecko 提供的 URL 下载图像,因此我们将编写一个实用程序类来帮助我们完成此操作。

import requests
import os
class Utils:
@staticmethod
def download_image(image_url: str) -> str:
project_root = os.getcwd()
file_name = image_url.split("/")[-1].split("?")[0]
file_path = os.path.join(project_root, file_name)
response = requests.get(image_url)
if response.status_code == 200:
with open(file_path, "wb") as image_file:
image_file.write(response.content)
return file_path
else:
raise Exception(
f"Failed to download image: {image_url}, status code: {response.status_code}"
)
@staticmethod
def delete_image(file_path: str) -> None:
if os.path.exists(file_path):
os.remove(file_path)
else:
print(f"File not found: {file_path}")
Util 类可以扩展以包含我们可能视为实用程序的任何方法,例如字符串或数字格式化,但现在它将帮助我们下载和删除图像,因为我们只想临时存储图像。

第六步:整合所有

现在我们已经开发了所有服务和辅助函数,是时候编写主脚本了。该脚本将定期分析各种加密货币,并在生成买入信号时向我们发送操作系统通知。

以下是我们的主要脚本工作原理的详细说明:

from services.coingecko_service import CoinGecko
from services.notification_service import Notification
from services.tradingview_service import TradingView
from tradingview_ta import Interval
from utils.util import Utils
import time
cg = CoinGecko()
def main():
coins = cg.get_all_coins()
for coin in coins:
print(coin.symbol)
try:
icon_path = Utils.download_image(coin.image)
analysis = TradingView.retrieve_analysis(
(coin.symbol + "USDT").capitalize(), "Binance", Interval.INTERVAL_1_HOUR
)
if (
analysis.oscillators["RECOMMENDATION"] == "BUY"
and analysis.moving_averages["RECOMMENDATION"] == "BUY"
):
Notification.send(
f"Buy signal for {coin.symbol.upper()}",
"Both Oscillators and Moving averages have generated a buy signal.",
icon_path,
)
except Exception as e:
print(e)
finally:
time.sleep(1)
Utils.delete_image(icon_path)
if __name__ == "__main__":
while True:
main()
time.sleep(300)
关键组件

我们脚本的主要功能首先使用cg.get_all_coins()获取所有可用的代币,并提供一个完整的列表以供分析。然后,它会遍历每个代币,打印其符号以跟踪正在处理的资产。

对于每种代币,脚本都会下载其关联的图像,如果生成买入信号,该图像将用于通知。接下来,它会检索该代币交易对兑 USDT 的交易分析,使用币安作为我们的 TradingView 价格数据源,并使用一小时的时间范围进行指标分析。

该脚本会检查振荡指标和移动平均线是否都发出买入建议。如果是,则会触发通知,提醒用户潜在的买入信号,为决策提供重要信息。

整个操作以无限循环运行,每五分钟执行一次main()函数。这可以持续监控市场状况,确保根据预设的交易信号及时发出警报。您可以根据自身需求和交易风格调整循环频率。

您可以直接从您喜欢的 IDE 运行代码,或者导航到项目的根目录并在 CMD 或终端窗口中执行以下命令:

python main.py
#or
python3 main.py
一旦脚本运行,只要满足您的条件,您就会开始看到屏幕上出现桌面通知。

Python交易信号通知


注意事项

一个关键的考虑因素是分析的阈值。如果生成买入信号的参数设置得过于宽松,可能会导致误报,并同时生成过多的信号。与其试图广撒网来捕捉潜在的买入信号,不如在分析中结合多个确认信号,专注于更强的买入信号,通常更为安全。 


目前,信号逻辑位于main.py 中,但可以将其移动到其自己的.yml文件中以便于访问。


此示例已开源,可在 Github上获取,方便快速上手。该应用程序可以进一步改进,在信号通知中包含更详细的消息以及资产的当前价格。还可以添加快捷操作,实现一键快速交易,让您可以立即根据信号采取行动。 


这为应用程序开辟了新的可能性,包括一个用于跟踪您的交易的分类账以及一种轻松绘制您的结果的方法。


虽然该脚本旨在帮助监控交易机会,但它应该补充强调仔细分析和负责任的决策的全面交易策略。

作者:GTokenTool一键发币平台

交流群:https://t.me/+Kz4u3xoDpFo3ZWY1

同类推荐