量化開發期間,每次都獲取券商數據,總是一個麻煩事。所以搭建一個原生的資料庫進行儲存,可以節約很多不必要的效能和資源開銷。一般情況下,建議使用clickhouse資料庫來當做你的資料庫儲存。不過本文章為了快速入門,就以postgresql為例來做資料庫儲存。
本地postgresql我使用的debian系統進行安裝。使用debian的原因:debian的shell操作可以相容更多的Linux系列作業系統,例如Ubuntu系列、華為歐拉系列、麒麟作業系統系列等。
步驟 1: 更新系統
首先,確保你的系統是最新的。開啟終端並執行:
sudoapt update
sudoapt upgrade
步驟 2: 安裝PostgreSQL
Debian的官方倉庫中包含了PostgreSQL。你可以直接安裝最新的PostgreSQL版本。執行以下命令來安裝:
sudo apt install postgresql
步驟 3: 啟動和啟用服務
安裝完成後,PostgreSQL服務通常會自動啟動。你可以檢查服務狀態:
sudo systemctl status postgresql
如果服務沒有執行,你可以啟動並設定開機啟動:
sudosystemctl start postgresql
sudosystemctl enable postgresql
步驟 4: 建立資料庫和使用者
安裝完畢後,你可以開始建立資料庫和使用者。首先,切換到postgres使用者:
sudo -i -u postgres
然後,你可以進入PostgreSQL命令列界面:
psql
在這裏,你可以建立一個新的使用者和資料庫,並授予使用者許可權:
CREATEUSER myuser WITH ENCRYPTED PASSWORD'mypassword';
CREATEDATABASE mydb;
GRANTALLPRIVILEGESONDATABASE mydb TO myuser;
授予public的許可權
-- 給予特定使用者對schema 的使用許可權
GRANTUSAGEONSCHEMA my_schema TO your_user;
-- 給予特定使用者對 schema 中所有表的所有許可權
GRANTALLONALLTABLESINSCHEMA my_schema TO your_user;
-- 設定預設許可權,以確保將來在 schema 中建立的所有新表都將自動給予特定使用者相應許可權
ALTERDEFAULTPRIVILEGESINSCHEMA my_schema GRANTALLONTABLESTO your_user;
結束psql使用\q,然後回到普通使用者使用exit。
步驟 5: 配置遠端存取
如果你需要遠端連線到你的PostgreSQL資料庫,你需要修改postgresql.conf和pg_hba.conf檔。這些檔通常位於/etc/postgresql/版本/main/目錄中。
【備註】我當前最新版本是15版本,如果以後你們下載的可能不是15版本,請根據實際版本進行配置。例如配置預設路徑裏面的15是實際你自己的版本,例如16、17、18等等。
編輯postgresql.conf,設定listen_addresses為'*':
sudo vim /etc/postgresql/15/main/postgresql.conf
在檔中找到listen_addresses並修改它:
listen_addresses = '*'
改變前:
改變後:
編輯pg_hba.conf,添加或修改規則以允許遠端連線:
sudo vim /etc/postgresql/15/main/pg_hba.conf
在合適的位置添加:
# TYPE DATABASE USER ADDRESS METHOD
hostallall 0.0.0.0/0 md5
重新開機PostgreSQL服務使更改生效:
sudo systemctl restart postgresql
然後可以使用一些客戶端工具來連線資料庫,例如DataGrip、Navicat、Dbeaver等等都可以。
並且裏面沒有任何表結構等資訊。
實作根據表名稱自動建立指定的表結構。用於存放所有大A的歷史數據。先建立一個實體類,並用來指定表欄位名稱,用於統一生成所有股票的表結構。
以及預留三個欄位,儲存DIF、DEA、MACD數據
建立一個簡單的幫助類,用於操作資料庫使用。並且例項建立以後,預設提供一個獲取sqlsugarscope物件的方法,以及獲取已有表資訊的集合。
最後提供一個建立表結構的方法,用於指定表結構所需要的實體類,以及表名稱。表名稱此處可以以股票程式碼為表名稱
對之前獲取股票清單的地方,做一個建立表的操作。此處為了簡單操作,大佬們可以對幫助類做其他拓展,以便於支持依賴註入等。
開始執行,可以看到表結構在持續性建立
展開任意一個表,可以看到欄位都被成功建立了。後續這些表就會被用於儲存對應表名稱的股票程式碼的所有歷史數據。
執行完畢以後,可以看到總共5361個表。
接下來,在資料庫操作幫助類裏面,新增CRUD有關操作
對獲取歷史數據的操作,做個改造,獲取歷史數據以後也計算DIF、DEA、MACD數據,並一起寫入資料庫:
執行獲取歷史任務job,可以看到刷刷刷的獲取記錄資訊。
開啟資料庫表,檢視數據,可以看見數據寫入成功,並且dif、dea、macd數據也都記錄成功。和通達信等app上面的數據也一致(app顯示的是四舍五入以後的數據)
等待程式執行完畢,整個歷史數據就生成成功了。歷史數據可以用來方便計算你的策略的歷史模擬戰績,形成你的個人財富。
以上只是拋磚引玉,大家還可以自行保存分鐘數據、周數據、每個交易日收盤以後自動新增當天數據等進行維護,此處就不一一列舉了。
資料庫核心操作幫助類,供參考:
public class DatabaseHelper
{
private DbTableInfo[] _initTables=new DbTableInfo[0];
private SqlSugarScope _sqlScope = null;
public DatabaseHelper()
{
_sqlScope = GetDbScope();
GetTableList(_sqlScope);
}
/// <summary>
/// 返回表名稱
/// </summary>
/// <returns></returns>
publicstring[] GetStockTableNames()
{
return _initTables.Select(x => x.Name).ToArray();
}
private SqlSugarScope GetDbScope()
{
var db = new SqlSugarScope(new ConnectionConfig()
{
ConnectionString = "Host=ip;Port=port;Username=username;Password=pwd;Database=dbname;",
DbType = DbType.PostgreSQL,
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute
});
return db;
}
/// <summary>
/// 獲取已有的資料庫表
/// </summary>
/// <param name="db"></param>
/// <param name="tableName"></param>
/// <returns></returns>
privatevoid GetTableList(SqlSugarScope db)
{
_initTables = db.DbMaintenance.GetTableInfoList(false).ToArray();
}
publicvoid CreateTableWithCustomName<T>(string tableName)
{
try
{
if (!_initTables.Any(x => x.Name == tableName))
{
_sqlScope.MappingTables.Add(typeof(T).Name, tableName);
// 透過動態指定表名來初始化或遷移表結構
_sqlScope.CodeFirst.InitTables<T>();
// 解除對映
_sqlScope.MappingTables.Remove(new MappingTable() { EntityName = typeof(T).Name });
}
else
{
Debug.WriteLine($"Table '{tableName}' already exists.");
}
}catch(Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
/// <summary>
/// 對映表
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tableName"></param>
privatevoid UseTable<T>(string tableName)
{
_sqlScope.MappingTables.Add(typeof(T).Name, tableName);
}
/// <summary>
/// 插入數據
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tableName"></param>
/// <param name="data"></param>
publicvoid InsertData<T>(string tableName, List<T> data) where T : class, new()
{
UseTable<T>(tableName);
_sqlScope.Insertable(data).ExecuteCommand();
_sqlScope.MappingTables.Clear(); // 清理對映以防止後續操作錯誤
}
/// <summary>
/// 查詢
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tableName"></param>
/// <returns></returns>
public List<T> QueryData<T>(string tableName) where T : class, new()
{
UseTable<T>(tableName);
var result = _sqlScope.Queryable<T>().ToList();
_sqlScope.MappingTables.Clear();
return result;
}
/// <summary>
/// 更新
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tableName"></param>
/// <param name="data"></param>
publicvoid UpdateData<T>(string tableName, List<T> data) where T : class, new()
{
UseTable<T>(tableName);
_sqlScope.Updateable(data).ExecuteCommand();
_sqlScope.MappingTables.Clear();
}
/// <summary>
/// 刪除數據
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tableName"></param>
/// <param name="data"></param>
publicvoid DeleteData<T>(string tableName,List<T> data) where T : class, new()
{
UseTable<T>(tableName);
_sqlScope.Deleteable(data).ExecuteCommand();
_sqlScope.MappingTables.Clear();
}
/// <summary>
/// 刪除指定的表
/// </summary>
/// <param name="tableName"></param>
publicvoid DropTableIfExists(string tableName)
{
if (_sqlScope.DbMaintenance.IsAnyTable(tableName, false))
{
_sqlScope.DbMaintenance.DropTable(tableName);
}
else
{
Debug.WriteLine($"Table {tableName} does not exist.");
}
}
}
谷市有風險,量化需謹慎~大佬們且量且珍惜~
如果覺得有幫助,歡迎點贊+轉發+收藏+關註【Dotnet Dancer】~謝謝大佬們,祝大佬們早日財富自由~