# .batμ€νμ λ¬Έμ μλλ‘ 'backtest'λͺ
μ κ°μνκ²½μ λ³Έ νλ‘μ νΈμμ λμΌ λλ ν 리μ μ€μΉ λΆνλ립λλ€.
# .
# βββ Backtest -> κ°μνκ²½
# βββ Project /
# β βββ api_test
# β βββ data
# β βββ import_price_data
# β βββ ...
python -m venv backtest
-
Windows
backtest\Scripts\activate
-
Linux
source backtest/bin/activate
# νλ‘μ νΈ ν΄λ/
pip install -r requirements.txt
PostgreSQLμμ backtest
DBμ μ μ λ₯Ό μλμ κ°μ΄ μμ±ν©λλ€:
CREATE DATABASE backtest;
CREATE USER backtest WITH PASSWORD 'backtest';
GRANT ALL PRIVILEGES ON DATABASE backtest TO backtest;
Linuxνκ²½μμ μ€νμ backtestλ‘ λ‘κ·ΈμΈνκΈ° μν΄ /etc/postgresql/{λ²μ }/main/pg_hba.conf μμ μΈμ¦λ°©μμ λ³κ²½ν΄μΌ ν μ μμ΅λλ€. Peer -> md5
DB μ°κ²° μ 보λ
.env
λλDATABASE_URL
νκ²½λ³μλ‘ κ΄λ¦¬ν©λλ€.
#env λ΄μ©μ
λλ€.
# μμΉ : μ΅μμ κ²½λ‘
DATABASE_URL = postgresql://backtest:[email protected]:5432/backtest
κ³Όμ λ΄μ© μ€ μ£Όμ΄μ§ κ°κ²©λ°μ΄ν°λ₯Ό λ°μ΄ν°λ² μ΄μ€μ λ£λ κ³Όμ μ λλ€.
# νλ‘μ νΈ ν΄λ/
python import_price_data.py
uvicorn main:app --reload
νλͺ© | λ΄μ© |
---|---|
Base URL | /backtest |
Response Format | JSON |
Auth | μμ |
- Method:
POST
- URL:
/backtest/run
- Description: μ λ ₯κ°μ λ°νμΌλ‘ λ°±ν μ€νΈ κ³μ° ν DBμ μ μ₯νκ³ κ²°κ³Ό λ°ν
{
"start_year": 2020,
"start_month": 1,
"trade_day": 10,
"initial_balance": 1000,
"fee_rate": 0.001,
"weight_months": 6
}
{
"data_id": 1,
"output": {
"total_return": 0.66,
"cagr": 0.1043,
"vol": 0.121,
"sharpe": 0.86,
"mdd": -0.1947
},
"last_rebalance_weight": [
["SPY", 0.5],
["QQQ", 0.5],
["BIL", 0.0]
]
}
- Method:
GET
- URL:
/backtest/
- Description: μ μ₯λ λͺ¨λ λ°±ν
μ€νΈ
data_id
μ λ§μ§λ§ 리밸λ°μ± λΉμ€ λ°ν
[
{
"data_id": 1,
"last_rebalance_weight": [["SPY", 0.5], ["QQQ", 0.5], ["BIL", 0.0]]
},
{
"data_id": 2,
"last_rebalance_weight": [["GLD", 0.5], ["QQQ", 0.5], ["BIL", 0.0]]
}
]
- Method:
GET
- URL:
/backtest/{data_id}
- Description: νΉμ
data_id
μ μ λ ₯κ° + ν΅κ³ + λ§μ§λ§ 리밸λ°μ± λΉμ€ λ°ν
{
"input": {
"start_year": 2020,
"start_month": 1,
"invest": 1000,
"trade_date": 10,
"cost": 0.001,
"caculate_month": 6
},
"output": {
"data_id": 1,
"total_return": 0.66,
"cagr": 0.1043,
"vol": 0.121,
"sharpe": 0.86,
"mdd": -0.1947
},
"last_rebalance_weight": [
["SPY", 0.5],
["QQQ", 0.5],
["BIL", 0.0]
]
}
- Method:
DELETE
- URL:
/backtest/{data_id}
- Description: νΉμ
data_id
μ λ°±ν μ€νΈ κ²°κ³Ό μμ
{
"data_id": 2
}
Endpoint | μ€λͺ |
---|---|
/backtest/test |
λ§€λ§€ date λ° ETF κ°κ²© DataFrameμ JSONμΌλ‘ λ°ν |
ETF κ°κ²©μ μ κΈ°μ μΌλ‘ μ λ°μ΄νΈνκΈ° μν λ°°μΉ μ€ν¬λ¦½νΈμ λλ€.
update_prices.bat
μμ
@echo off
cd /d "%~dp0"
call "..\{κ°μνκ²½ μ΄λ¦λ¦}\Scripts\activate.bat"
python update_prices.py
-
μμ μ€μΌμ€λ¬(Task Scheduler)μμ
.bat
νμΌμ μνλ μκ°λμ μ€ν λ±λ‘ -
ν¬λ‘€λ§ μ EST μκ°μΌλ‘ μ§ννκΈ° λλ¬Έμ νμ¬ μκ°μΈ KST(UTC+9) κΈ°μ€ μ€μ 8μμ μ€νμν€λλ‘ λ±λ‘νλ©΄ λ©λλ€.
1. νΈμ§κΈ° μ΄κΈ°
crontab -e
2. μλ λ΄μ© μΆκ° (KST κΈ°μ€ λ§€μΌ μ€μ 8μ μ€ν)
0 8 * * * /home/username/κ°μνκ²½ κ²½λ‘/bin/python /home/username/νλ‘μ νΈ κ²½λ‘/update_prices.py
venv
κ²½λ‘μupdate_prices.py
κ²½λ‘λ μ€μ νκ²½μ λ§κ² μμ ν΄μ£ΌμΈμ.
λ°°μΉ νλ‘κ·Έλ¨ ν μ€νΈ μ§ν μ€ bat νμΌμ μ€νμν€λ©΄ λ°μ΄ν°κ° μ λ ₯ λ κ²μ΄λΌ μκ°νμ¬ νΈλ¦¬ν ν μ€νΈλ₯Ό μν΄ μλ SQLλ¬Έμ λ£μμ΅λλ€.
# psqlλ΄ μ€ν -> κΈ°μ‘΄ λ°μ΄ν° μμ λ° μΈλ±μ€ μ΄κΈ°ν
TRUNCATE TABLE prices RESTART IDENTITY;
DBμ΄κΈ°ν μ΄ν import_price_dataλ₯Ό λ€μνλ² μ€νμν€λ©΄ λ¬Έμ μμ΄ μ§ν λ κ²μ΄λΌ μκ°ν©λλ€.
python import_price_data.py
.
βββ api_test/
β βββ main.py
β βββ database.py
β βββ schemas.bat
β βββ routes/
β βββ services/
β βββ migrations/
βββ data/
β βββ price_data.csv
βββ requirements.txt
βββ update_prices.bat
βββ update_prices.log
βββ update_prices.py
- μ£Όλ§(EST κΈ°μ€)μλ κ°κ²©μ΄ μ λ°μ΄νΈλμ§ μμ΅λλ€.