Type/to search
8
Follow
1363
Followers
বাজার সংগ্রাহক আবার আপগ্রেড করা হয়েছে - CSV ফর্ম্যাট ফাইল আমদানি সমর্থন করে এবং কাস্টমাইজড ডেটা উত্স প্রদান করে৷
Discussions
Created 2020-05-23 15:44:47  Updated 2024-12-10 20:19:56
 24
 2905

img

বাজার সংগ্রাহক আবার আপগ্রেড করা হয়েছে - CSV ফর্ম্যাট ফাইল আমদানি সমর্থন করে এবং কাস্টমাইজড ডেটা উত্স প্রদান করে৷

সম্প্রতি, একজন ব্যবহারকারীকে উদ্ভাবকের পরিমাণগত ট্রেডিং প্ল্যাটফর্মের ব্যাকটেস্টিং সিস্টেমের জন্য ডেটা উৎস হিসাবে তার নিজস্ব CSV ফর্ম্যাট ফাইল ব্যবহার করতে হবে। ইনভেনটর কোয়ান্টিটেটিভ ট্রেডিং প্ল্যাটফর্মের ব্যাকটেস্টিং সিস্টেমের অনেকগুলি ফাংশন রয়েছে এবং এটি ব্যবহার করা সহজ এবং কার্যকর এইভাবে, যতক্ষণ আপনার কাছে ডেটা থাকে, আপনি ব্যাকটেস্টিং পরিচালনা করতে পারেন এবং এটি আর এক্সচেঞ্জ এবং বৈচিত্র্যের মধ্যে সীমাবদ্ধ নয়। প্ল্যাটফর্ম ডেটা সেন্টার।

ডিজাইনের ধারণা

ডিজাইন আইডিয়াটি আসলে খুবই সহজ আমাদের শুধুমাত্র পূর্ববর্তী মার্কেট কালেক্টরের উপর ভিত্তি করে একটি প্যারামিটার যোগ করতে হবে।isOnlySupportCSVব্যাকটেস্টিং সিস্টেমে সরবরাহ করার জন্য শুধুমাত্র CSV ফাইলগুলিকে ডেটা উত্স হিসাবে ব্যবহার করা হবে কিনা তা নিয়ন্ত্রণ করতে এবং অন্য প্যারামিটার যোগ করতে ব্যবহৃত হয়filePathForCSV, যে সার্ভারে মার্কেট কালেক্টর রোবট চলে সেখানে CSV ডেটা ফাইলের পাথ সেট করতে ব্যবহৃত হয়। অবশেষে, অনুসারেisOnlySupportCSVপ্যারামিটার সেট করা আছে কিনাTrueকোন ডেটা উৎস ব্যবহার করবেন তা নির্ধারণ করতে (1. নিজের দ্বারা সংগৃহীত, 2. CSV ফাইলে ডেটা), এই পরিবর্তনটি মূলতProviderক্লাসdo_GETফাংশনে

একটি CSV ফাইল কি?

কমা-বিচ্ছিন্ন মান (CSV, কখনও কখনও অক্ষর-বিচ্ছিন্ন মানও বলা হয় কারণ সীমানা নির্ধারণকারী অক্ষরগুলি কমা ব্যতীত অন্য কিছু হতে পারে) হল এমন ফাইল যা সরল পাঠ্যে ট্যাবুলার ডেটা (সংখ্যা এবং পাঠ্য) সংরক্ষণ করে। প্লেইন টেক্সটের অর্থ হল ফাইলটি অক্ষরের একটি ক্রম এবং এতে এমন কোনও ডেটা নেই যা বাইনারি সংখ্যার মতো ব্যাখ্যা করা উচিত। একটি CSV ফাইলে যেকোনো সংখ্যক রেকর্ড থাকে, যেগুলো কোন না কোন লাইন ব্রেক ক্যারেক্টার দ্বারা আলাদা করা থাকে; প্রতিটি রেকর্ডে ফিল্ড থাকে এবং ফিল্ডের মধ্যে বিভাজক হল অন্যান্য ক্যারেক্টার বা স্ট্রিং, যার মধ্যে সবচেয়ে সাধারণ হল কমা বা ট্যাব। সাধারণত, সমস্ত রেকর্ডের ক্ষেত্রের ক্রম ঠিক একই রকম থাকে। এগুলো সাধারণত প্লেইন টেক্সট ফাইল। এটি খোলার জন্য WORDPAD অথবা Notepad ব্যবহার করার পরামর্শ দেওয়া হচ্ছে। আরেকটি পদ্ধতি হল এটিকে একটি নতুন ফাইল হিসেবে সংরক্ষণ করা এবং তারপর EXCEL দিয়ে খোলা।

CSV ফাইল ফরম্যাটের জন্য কোন সার্বজনীন মান নেই, তবে কিছু নিয়ম আছে, সাধারণত প্রতি লাইনে একটি রেকর্ড থাকে এবং প্রথম লাইনটি শিরোনাম। প্রতিটি সারির ডেটা কমা দ্বারা পৃথক করা হয়।

উদাহরণ স্বরূপ, আমরা পরীক্ষার জন্য যে CSV ফাইলটি ব্যবহার করেছি সেটি নোটপ্যাড দিয়ে খোলা হলে এরকম দেখায়:
img

লক্ষ্য করুন যে CSV ফাইলের প্রথম লাইন হল টেবিল হেডার।

,open,high,low,close,vol

আমাদের শুধু এই ধরনের ডেটা পার্স এবং সংগঠিত করতে হবে, এবং তারপরে এটিকে ব্যাকটেস্ট সিস্টেমের কাস্টম ডেটা উৎসের জন্য প্রয়োজনীয় বিন্যাসে তৈরি করতে হবে এটি আমাদের পূর্ববর্তী নিবন্ধে কোডে প্রক্রিয়া করা হয়েছে এবং শুধুমাত্র সামান্য পরিবর্তন করা প্রয়োজন।

সংশোধিত কোড

import _thread import pymongo import json import math import csv from http.server import HTTPServer, BaseHTTPRequestHandler from urllib.parse import parse_qs, urlparse def url2Dict(url): query = urlparse(url).query params = parse_qs(query) result = {key: params[key][0] for key in params} return result class Provider(BaseHTTPRequestHandler): def do_GET(self): global isOnlySupportCSV, filePathForCSV try: self.send_response(200) self.send_header("Content-type", "application/json") self.end_headers() dictParam = url2Dict(self.path) Log("自定义数据源服务接收到请求,self.path:", self.path, "query 参数:", dictParam) # 目前回测系统只能从列表中选择交易所名称,在添加自定义数据源时,设置为币安,即:Binance exName = exchange.GetName() # 注意,period为底层K线周期 tabName = "%s_%s" % ("records", int(int(dictParam["period"]) / 1000)) priceRatio = math.pow(10, int(dictParam["round"])) amountRatio = math.pow(10, int(dictParam["vround"])) fromTS = int(dictParam["from"]) * int(1000) toTS = int(dictParam["to"]) * int(1000) # 要求应答的数据 data = { "schema" : ["time", "open", "high", "low", "close", "vol"], "data" : [] } if isOnlySupportCSV: # 处理CSV读取,filePathForCSV路径 listDataSequence = [] with open(filePathForCSV, "r") as f: reader = csv.reader(f) # 获取表头 header = next(reader) headerIsNoneCount = 0 if len(header) != len(data["schema"]): Log("CSV文件格式有误,列数不同,请检查!", "#FF0000") return for ele in header: for i in range(len(data["schema"])): if data["schema"][i] == ele or ele == "": if ele == "": headerIsNoneCount += 1 if headerIsNoneCount > 1: Log("CSV文件格式有误,请检查!", "#FF0000") return listDataSequence.append(i) break # 读取内容 while True: record = next(reader, -1) if record == -1: break index = 0 arr = [0, 0, 0, 0, 0, 0] for ele in record: arr[listDataSequence[index]] = int(ele) if listDataSequence[index] == 0 else (int(float(ele) * amountRatio) if listDataSequence[index] == 5 else int(float(ele) * priceRatio)) index += 1 data["data"].append(arr) Log("数据:", data, "响应回测系统请求。") self.wfile.write(json.dumps(data).encode()) return # 连接数据库 Log("连接数据库服务,获取数据,数据库:", exName, "表:", tabName) myDBClient = pymongo.MongoClient("mongodb://localhost:27017") ex_DB = myDBClient[exName] exRecords = ex_DB[tabName] # 构造查询条件:大于某个值{'age': {'$gt': 20}} 小于某个值{'age': {'$lt': 20}} dbQuery = {"$and":[{'Time': {'$gt': fromTS}}, {'Time': {'$lt': toTS}}]} Log("查询条件:", dbQuery, "查询条数:", exRecords.find(dbQuery).count(), "数据库总条数:", exRecords.find().count()) for x in exRecords.find(dbQuery).sort("Time"): # 需要根据请求参数round和vround,处理数据精度 bar = [x["Time"], int(x["Open"] * priceRatio), int(x["High"] * priceRatio), int(x["Low"] * priceRatio), int(x["Close"] * priceRatio), int(x["Volume"] * amountRatio)] data["data"].append(bar) Log("数据:", data, "响应回测系统请求。") # 写入数据应答 self.wfile.write(json.dumps(data).encode()) except BaseException as e: Log("Provider do_GET error, e:", e) def createServer(host): try: server = HTTPServer(host, Provider) Log("Starting server, listen at: %s:%s" % host) server.serve_forever() except BaseException as e: Log("createServer error, e:", e) raise Exception("stop") def main(): LogReset(1) if (isOnlySupportCSV): try: # _thread.start_new_thread(createServer, (("localhost", 9090), )) # 本机测试 _thread.start_new_thread(createServer, (("0.0.0.0", 9090), )) # VPS服务器上测试 Log("开启自定义数据源服务线程,数据由CSV文件提供。", "#FF0000") except BaseException as e: Log("启动自定义数据源服务失败!") Log("错误信息:", e) raise Exception("stop") while True: LogStatus(_D(), "只启动自定义数据源服务,不收集数据!") Sleep(2000) exName = exchange.GetName() period = exchange.GetPeriod() Log("收集", exName, "交易所的K线数据,", "K线周期:", period, "秒") # 连接数据库服务,服务地址 mongodb://127.0.0.1:27017 具体看服务器上安装的mongodb设置 Log("连接托管者所在设备mongodb服务,mongodb://localhost:27017") myDBClient = pymongo.MongoClient("mongodb://localhost:27017") # 创建数据库 ex_DB = myDBClient[exName] # 打印目前数据库表 collist = ex_DB.list_collection_names() Log("mongodb ", exName, " collist:", collist) # 检测是否删除表 arrDropNames = json.loads(dropNames) if isinstance(arrDropNames, list): for i in range(len(arrDropNames)): dropName = arrDropNames[i] if isinstance(dropName, str): if not dropName in collist: continue tab = ex_DB[dropName] Log("dropName:", dropName, "删除:", dropName) ret = tab.drop() collist = ex_DB.list_collection_names() if dropName in collist: Log(dropName, "删除失败") else : Log(dropName, "删除成功") # 开启一个线程,提供自定义数据源服务 try: # _thread.start_new_thread(createServer, (("localhost", 9090), )) # 本机测试 _thread.start_new_thread(createServer, (("0.0.0.0", 9090), )) # VPS服务器上测试 Log("开启自定义数据源服务线程", "#FF0000") except BaseException as e: Log("启动自定义数据源服务失败!") Log("错误信息:", e) raise Exception("stop") # 创建records表 ex_DB_Records = ex_DB["%s_%d" % ("records", period)] Log("开始收集", exName, "K线数据", "周期:", period, "打开(创建)数据库表:", "%s_%d" % ("records", period), "#FF0000") preBarTime = 0 index = 1 while True: r = _C(exchange.GetRecords) if len(r) < 2: Sleep(1000) continue if preBarTime == 0: # 首次写入所有BAR数据 for i in range(len(r) - 1): bar = r[i] # 逐根写入,需要判断当前数据库表中是否已经有该条数据,基于时间戳检测,如果有该条数据,则跳过,没有则写入 retQuery = ex_DB_Records.find({"Time": bar["Time"]}) if retQuery.count() > 0: continue # 写入bar到数据库表 ex_DB_Records.insert_one({"High": bar["High"], "Low": bar["Low"], "Open": bar["Open"], "Close": bar["Close"], "Time": bar["Time"], "Volume": bar["Volume"]}) index += 1 preBarTime = r[-1]["Time"] elif preBarTime != r[-1]["Time"]: bar = r[-2] # 写入数据前检测,数据是否已经存在,基于时间戳检测 retQuery = ex_DB_Records.find({"Time": bar["Time"]}) if retQuery.count() > 0: continue ex_DB_Records.insert_one({"High": bar["High"], "Low": bar["Low"], "Open": bar["Open"], "Close": bar["Close"], "Time": bar["Time"], "Volume": bar["Volume"]}) index += 1 preBarTime = r[-1]["Time"] LogStatus(_D(), "preBarTime:", preBarTime, "_D(preBarTime):", _D(preBarTime/1000), "index:", index) # 增加画图展示 ext.PlotRecords(r, "%s_%d" % ("records", period)) Sleep(10000)

পরীক্ষা চালান

প্রথমে, আমরা বাজার সংগ্রাহক রোবট শুরু করি, রোবটে একটি বিনিময় যোগ করি এবং রোবটটিকে চলতে দেই।
পরামিতি কনফিগারেশন:
img

img

তারপরে আমরা একটি পরীক্ষার কৌশল তৈরি করি:

function main() { Log(exchange.GetRecords()) Log(exchange.GetRecords()) Log(exchange.GetRecords()) }

কৌশলটি খুবই সহজ, মাত্র তিনবার কে-লাইন ডেটা পান এবং মুদ্রণ করুন।

ব্যাকটেস্ট পৃষ্ঠায়, ব্যাকটেস্ট সিস্টেমের ডেটা উত্সটিকে একটি কাস্টম ডেটা উত্সে সেট করুন এবং সার্ভারের ঠিকানাটি পূরণ করুন যেখানে বাজার সংগ্রাহক রোবট চলে৷ যেহেতু আমাদের CSV ফাইলের ডেটা 1-মিনিটের K-লাইন। অতএব, ব্যাকটেস্টিংয়ের সময়, আমরা কে-লাইন সময়কাল 1 মিনিটে সেট করি।

img

ব্যাকটেস্টিং শুরু করতে ক্লিক করুন, এবং বাজার সংগ্রাহক রোবট ডেটা অনুরোধ পেয়েছে:
img

ব্যাকটেস্টিং সিস্টেম কৌশলটি কার্যকর করার পরে, এটি ডেটা উত্সের কে-লাইন ডেটার উপর ভিত্তি করে একটি কে-লাইন চার্ট তৈরি করে।
img

ফাইলের ডেটা তুলনা করুন:
img

img

RecordsCollecter (কাস্টম ডেটা সোর্স ফাংশন প্রদানের জন্য আপগ্রেড করা হয়েছে, ডেটা উত্স প্রদান করতে CSV ডেটা ফাইলগুলিকে সমর্থন করে)

আপনার কোন পরামর্শ থাকলে, একটি বার্তা ছেড়ে দিন.

Related Recommendations
Comment
All comments (24)

    托管者服务器上需要安装python吗?

    3 years ago

    需要有python。

    3 years ago

    梦神,现在这个自定义数据源再浏览器端回测,数据精度有问题,你试试看

    5 years ago

    API 文档上有关于精度的说明,可以看下试下。

    5 years ago

    是回测系统bug,已经修复了

    5 years ago

    img img
    挂好机器人了,网址那里应该怎么填啊,我填的服务器地址端口号9090收集器那里也没反应

    5 years ago

    需要看明白文章,代码。这里是讲用CSV文件做数据源,给回测系统提供数据。

    5 years ago

    请问一下,为什么我在托管服务器上面设置好了自定义CSV数据源,用页面请求有数据的返回,然后在回测中没有数据的返回,当把数据直接设置为只有俩个数据的时候httpserver服务端可以接收请求中, img img img img img

    6 years ago

    请问一下,为什么我在托管服务器上面设置好了自定义CSV数据源,用页面请求有数据的返回,然后在回测中没有数据的返回,并且没有请求到httpserver服务端中 img img img img img

    6 years ago

    你在浏览器端可以是因为 你指定写的查询参数, 回测系统 触发不了 机器人 应答,说明机器人没接受到请求, 说明回测时那个地方配置错了, 检查下,调试下就能找到问题。

    6 years ago

    少数据量获取是能够获取的,但是当我指定一个CSV文件一年多一分钟数据的时候发现就不能获取了,是不是数据量太大有影响?然后这个可以本地化开启自定义数据源,然后本地进行回测吗?

    6 years ago

    数据量大也可以的,我测试的时候测试过。

    6 years ago

    我目前在机器人上配置的就是HUOBI交易所,然后交易对也是设置的BTC-USDT,回测时也是这么配置的,然后回测的代码也就是使用的一个exchange.GetRecords()函数,这个定义的数据有要求吗?比如时间部分毫秒以及秒都能进行查看吗?

    6 years ago

    交易对BTC_USDT,你具体指的是哪个?【这个定义的数据有要求吗?比如时间部分毫秒以及秒都能进行查看吗?】。

    6 years ago

    我是csv数据是一分钟K线是其他币种的数据,然后由于回测的时候交易对不能随便选择,则机器人跟回测选择的交易所就都设置的为huobi,交易对为BTC-USDT,这个请求数据我是有时机器人那边能接收到请求,但是回测这边获取不到数据,并且我把csv的时间戳从秒改成了毫秒也是不能获取数据的。不知道有没有什么方式可以本地回测数据进行调优,当策略进行调参调优的时候,网页端会崩溃

    6 years ago

    数据量太大 网页承载不了,另外DEMO 你研究下,应该没问题的,估计你那里设置错了。

    6 years ago

    请问一下 怎么可以在本地起http服务端 本地回测数据, 是不是本地回测不支持回测自定义数据源?我在本地回测添加exchanges: [{"eid":"Huobi","currency":"ETH_USDT","feeder":"http://127.0.0.1:9090"}]这种参数,以及改成机器人的IP也是没有请求到服务端

    6 years ago

    这个提供自定义数据源的服务必须放在 服务器上,必须是公网IP。本地的服务回测系统访问不到。

    6 years ago

    自定义数据使用exchange.GetData()方式,用于回测可以让K线变成自定义数据吗?

    6 years ago

    参看API 文档上的描述。

    6 years ago

    请问参数是怎么设置的呀

    6 years ago

    按照本文图中设置就可以,如果要读取自己的CSV文件,设置这个文件的路径就可以了。

    6 years ago

    高级,这样就能测任何币了,或许股票也可以。

    6 years ago

    666

    6 years ago
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)