Jinsi ya kufanya backtest ya Python bila API key
Jifunze kuendesha backtest ya Python inayoweza kurudiwa kwa kutumia data tuli na toleo maalum la maktaba. Gundua mapungufu ya siri ya mkondo wa faida katika uchambuzi wako.
Uhakiki wa backtest inayoweza kurudiwa
Backtest inayoweza kurudiwa katika Python ni ile ambayo mgeni anaweza kuiendesha tena kwenye kompyuta safi na kupata namba zako kamili, bila kuhitaji akaunti au API key. Mafunzo mengi hushindwa mtihani huo katika mstari wa kwanza, ambapo upakuaji wa data ya moja kwa moja humpa msomaji anayefuata historia ya bei inayotofautiana kidogo na ile aliyopata mwandishi. Mwongozo huu unatumia injini moja ya chanzo huria, quantjourney-bt katika toleo la 0.12.4, unaendesha mfano wake uliounganishwa bila kuhitaji vitambulisho vyovyote, kisha unatumia data halisi ya soko kuonyesha kile ambacho uendeshaji mmoja safi bado hauwezi kukuambia.
Ni nini hufanya backtest iweze kurudiwa?
Katika muktadha huu, uwezo wa kurudiwa una maana finyu na inayoweza kupimika: mtu wa pili anaendesha amri moja kwenye mashine safi na kupata namba zako hadi desimali ya mwisho. Mambo mawili ya kawaida huivunja hali hii.
La kwanza ni kodi. Maktaba iliyo katika toleo la 0.x haina ahadi ya utangamano kati ya matoleo madogo. Kubadilishwa kwa jina, kubadilishwa kwa mipangilio chaguo-msingi, au kupangwa upya kwa safu wima, kunaweza kufanya hati yako iendelee kufanya kazi huku ikitoa matokeo tofauti kimyakimya.
La pili ni data. Mafunzo ambayo mstari wake wa kwanza ni upakuaji wa moja kwa moja kutoka mtandaoni hayakuwahi kuwa na uwezo wa kurudiwa. Wauzaji hurekebisha historia, hufanya marekebisho ya splits, na kujaza mapengo, na hati hiyo hiyo huchapisha namba tofauti mwezi mmoja baadaye. Baada ya tukio kutokea, huwezi kutofautisha mabadiliko ya kodi na mabadiliko ya data.
Muundo unaofaa kuigwa kutoka kwa mradi huu ni kuoanisha toleo la injini lililothibitiwa na seti ndogo ya data iliyofungashwa ambayo husafirishwa ndani ya kifurushi chenyewe.
Weka usakinishaji: pip install quantjourney-bt==0.12.4
quantjourney-bt ni mfumo wa backtester wa QuantJourney, uliotolewa chini ya Leseni ya Apache 2.0 na unaohitaji Python 3.11 au toleo jipya zaidi. Toleo la 0.12.4 lilichapishwa tarehe ishirini na moja Julai 2026, na ndilo toleo ambalo kila amri hapa chini inarejelea, kama ilivyoandikwa mnamo Agosti 2026.
Fanya kazi ndani ya mazingira yaliyotengwa. python3 -m venv .venv hutengeneza mazingira hayo, source .venv/bin/activate huingia ndani yake, na python -m pip install -U pip husasisha kisakinishi ndani yake. Kisha chukua toleo kamili: pip install quantjourney-bt==0.12.4.
Mradi huu unaandika fomu isiyofungwa, pip install quantjourney-bt. Sehemu ya ==0.12.4 ni jukumu lako, na katika toleo la 0.x inajilipia yenyewe. Andika pin hiyo mahali ambapo mtu anayefuata ataikuta: pip freeze > requirements.txt hunasa kila utegemezi uliotatuliwa, ikiwemo ile ambayo hukuitaja kamwe.
Kuna nyongeza mbili za hiari. pip install "quantjourney-bt[wf]" huongeza Optuna kwa ajili ya mifano ya walk-forward na optimization. pip install "quantjourney-bt[data]" huongeza yfinance fallback inayotumiwa kwa ajili ya benchmarks.
Apache-2.0 ni leseni inayoruhusu mengi. Unaweza kutumia na kurekebisha msimbo huo kibiashara, unahifadhi faili za leseni na notisi pamoja na usambazaji wowote, na wachangiaji hutoa haki za hataza kwa uwazi.
Jinsi ya kuendesha mfano wa SMA uliounganishwa bila API key
Hazina hii inakuja na hati ya uzinduzi pamoja na mikakati hamsini ya mfano inayoweza kuendeshwa, iliyogawanywa katika njia inayozingatia uzito na njia inayozingatia oda, ikiwa na mitiririko mitano ya walk-forward kati yao. ./strategy.sh --list huchapisha katalogi. ./strategy.sh example_weights_01_sma_daily --check huleta mkakati mmoja na haigusi data yoyote, ambayo ndiyo njia ya haraka zaidi ya kuthibitisha kuwa usakinishaji ni sahihi.
Uendeshaji wa demo yenyewe ni mstari mmoja: ./strategy.sh example_weights_01_sma_daily --sample-data --output /tmp/qj-sample
Bendera ya --sample-data ndiyo inayobeba hoja nzima. Mradi huu unaelezea seti ya data iliyo nyuma yake kwa njia hii:
Seti ya data ya sampuli ni ndogo kimakusudi na inaweza kuzalishwa upya. Ni muhimu kwa ukaguzi wa usakinishaji, utengenezaji wa ripoti, na kusoma mtiririko wa injini bila kuhitaji kufungua akaunti.
Chanzo: quantjourney-bt README, toleo la 0.12.4, iliyosomwa tarehe 6 Agosti 2026.
Uendeshaji huo huandika saraka badala ya uamuzi wa konsooli: summary.txt na summary.json, metrics.csv, equity_curve.csv kando ya equity_curve.png yake, dashboard.html, folda ya plots/, na run_metadata.json inayorekodi jinsi uendeshaji ulivyosanidiwa. Faili hiyo ya mwisho ndiyo ambayo watu wengi huiruka na ndiyo inayofanya matokeo yaweze kukaguliwa mwaka mmoja baadaye.
Soma metriki zinazotokana na hapo kwa uaminifu. Seti ya data iliyounganishwa ni ndogo na ya kielelezo, kwa hivyo Sharpe ratio na maximum drawdown zilizochapishwa katika summary.txt zinaelezea faili ya sampuli. Si ushahidi kuhusu mkakati, na kuzichukulia kama matokeo ndiyo kosa la kwanza unaloweza kufanya.
Kile ambacho uendeshaji huo unathibitisha kina thamani: usakinishaji unafanya kazi, na mtiririko kamili wa injini, kuanzia ishara hadi uzito wa lengo hadi thamani ya kwingineko iliyoundwa upya, hutoa matokeo yake kwenye mashine yako bila kuhitaji kitambulisho chochote. Njia yenye vitambulisho ya kufikia huduma ya data ya mradi huo ipo kwa ajili ya backtests kwenye historia halisi. Njia hiyo imeandikwa, na mwongozo huu unaishia hapa, katika sehemu ambayo haihitaji chochote kutoka kwa mtu yeyote.
Kile ambacho mkondo mmoja wa equity wa ndani ya sampuli haukuambii
Majaribio ya sampuli huchora mkondo mmoja wa equity. Haya ndiyo mambo ambayo mkondo huo hauwezi kufanya, yakipimwa kwa data halisi ya soko badala ya faili ya maonyesho.
Jopo hapa chini linachukua wazo lilelile linalotumiwa na mkakati wa mfano, moving average ya vipindi ishirini inayovuka ile ya vipindi hamsini, inalitumia kwenye SPY, na kuripoti kila mwaka wa kalenda kando kuanzia mwaka elfu mbili na kumi na saba hadi elfu mbili na ishirini na tano. Nafasi katika kila kipindi hupangwa na bei ya kufunga ya kipindi kilichotangulia, kwa hivyo kanuni haifanyi biashara kwa kutumia namba ambayo haikuwa nayo bado.
SQL halisi nyuma ya kila namba
WITH daily AS
(
SELECT
toDate(toTimeZone(window_start, 'America/New_York')) AS d,
toFloat64(argMax(close, window_start)) AS px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= '2016-01-01 00:00:00'
AND window_start < '2026-01-01 05:00:00'
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) >= 570
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) < 960
GROUP BY d
),
averaged AS
(
SELECT
d,
px,
avg(px) OVER (ORDER BY d ROWS BETWEEN 19 PRECEDING AND CURRENT ROW) AS fast_ma,
avg(px) OVER (ORDER BY d ROWS BETWEEN 49 PRECEDING AND CURRENT ROW) AS slow_ma,
row_number() OVER (ORDER BY d) AS session_no
FROM daily
),
positioned AS
(
SELECT
d,
px,
if(session_no >= 50 AND fast_ma > slow_ma, 1, 0) AS long_today,
lagInFrame(if(session_no >= 50 AND fast_ma > slow_ma, 1, 0), 1)
OVER (ORDER BY d ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS long_prior,
lagInFrame(px, 1)
OVER (ORDER BY d ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS px_prior
FROM averaged
)
SELECT
toYear(d) AS year,
round((exp(sum(log(if(long_prior = 1, px / px_prior, 1.0)))) - 1) * 100, 1) AS rule_pct,
round((exp(sum(log(px / px_prior))) - 1) * 100, 1) AS hold_pct,
countIf(long_today != long_prior) AS crossover_count
FROM positioned
WHERE px_prior > 0
AND toYear(d) >= 2017
GROUP BY year
ORDER BY yearKanuni moja isiyobadilika, iliyopimwa mara 9. Soma safu wima mbili za asilimia kabla ya kusoma kitu kingine chochote. Katika 2017 kanuni ilimaliza mwaka kwa 16% dhidi ya 19.4% kwa kushikilia SPY katika kipindi hicho hicho. Katika 2025 safu wima hizo mbili zinasoma 10.4% na 16.4%. Msimbo ni sawa katika safu zote mbili. Dirisha pekee ndilo lilibadilika.
Safu wima ya crossover inaonyesha jinsi ushahidi wa msingi unavyokuwa hafifu. Mabadiliko ya nafasi 4 katika 2025 inamaanisha kuwa mwaka mzima wa mkondo wa equity unategemea maamuzi machache tu, ambayo ni sampuli ndogo sana ya kuita matokeo.
Je, kanuni hiyo hiyo hufanya kazi kwa njia sawa kwenye majina mengine?
Kubadilisha muda wa tarehe ni njia moja ya kuchunguza mkondo mmoja. Kubadilisha ulimwengu wa uwekezaji ni njia nyingine. Jopo hapa chini linashikilia vigezo bila kubadilika na kutumia kanuni inayofanana kwenye majina matano yenye ukwasi mkubwa katika kipindi cha miaka mitano ya kalenda kuanzia mwaka 2021 hadi 2025.
SQL halisi nyuma ya kila namba
WITH daily AS
(
SELECT
ticker,
toDate(toTimeZone(window_start, 'America/New_York')) AS d,
toFloat64(argMax(close, window_start)) AS px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ', 'AAPL', 'MSFT', 'KO')
AND window_start >= '2020-07-01 00:00:00'
AND window_start < '2026-01-01 05:00:00'
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) >= 570
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) < 960
GROUP BY ticker, d
),
averaged AS
(
SELECT
ticker,
d,
px,
avg(px) OVER (PARTITION BY ticker ORDER BY d ROWS BETWEEN 19 PRECEDING AND CURRENT ROW) AS fast_ma,
avg(px) OVER (PARTITION BY ticker ORDER BY d ROWS BETWEEN 49 PRECEDING AND CURRENT ROW) AS slow_ma,
row_number() OVER (PARTITION BY ticker ORDER BY d) AS session_no
FROM daily
),
positioned AS
(
SELECT
ticker,
d,
px,
lagInFrame(if(session_no >= 50 AND fast_ma > slow_ma, 1, 0), 1)
OVER (PARTITION BY ticker ORDER BY d ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS long_prior,
lagInFrame(px, 1)
OVER (PARTITION BY ticker ORDER BY d ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS px_prior
FROM averaged
)
SELECT
ticker AS symbol,
round((exp(sum(log(if(long_prior = 1, px / px_prior, 1.0)))) - 1) * 100, 1) AS rule_pct,
round((exp(sum(log(px / px_prior))) - 1) * 100, 1) AS hold_pct,
round(avg(long_prior) * 100, 0) AS days_long_pct
FROM positioned
WHERE px_prior > 0
AND d >= toDate('2021-01-01')
GROUP BY symbol
ORDER BY rule_pct DESCQQQ inakaa juu ya jopo katika 40.2%, na safu ya chini, KO, inakuja katika 3.8%. Safu ya days_long_pct inaripoti ni kiasi gani cha muda wa dirisha kila toleo lilitumia kushikilia chochote kile, 67% kwa safu ya juu. Seti moja ya vigezo, ulimwengu mitano, na spread pana kiasi kwamba kuchagua mshindi baada ya tukio hakusemi chochote kuhusu utendaji ambao bado hujaufanya.
Hakuna hata moja ya haya inayopendekeza kufanya biashara ya crossover. Crossover ni kipimo cha backtest, na backtest ndicho tunachokipima.
Mahali ambapo upendeleo wa kutazama mbele (look-ahead bias) hujipenyeza kwenye backtest ya uzani
Injini inayotumia uzani hubadilisha ishara kuwa uzani unaolengwa, huiga utekelezaji wa oda (fills) dhidi ya uzani huo, kisha hujenga upya thamani ya kwingineko kutokana na nafasi zilizotokana na hatua hizo. Hitilafu hujificha kwenye muunganiko kati ya ishara na uzani. Ikiwa uzani wa leo unatokana na bei ya kufunga ya leo na kisha kupata faida ya leo, backtest hiyo imefanya biashara kwa kutumia taarifa ambazo hazikuwepo wakati oda ingekuwa imewasilishwa. Huo ndio look-ahead bias, na haitoi ujumbe wa hitilafu. Inafanya kila kitu kionekane bora tu.
Jopo hapa chini linaendesha matoleo yote mawili ya kanuni moja juu ya historia ileile ya SPY.
SQL halisi nyuma ya kila namba
WITH daily AS
(
SELECT
toDate(toTimeZone(window_start, 'America/New_York')) AS d,
toFloat64(argMax(close, window_start)) AS px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= '2016-01-01 00:00:00'
AND window_start < '2026-01-01 05:00:00'
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) >= 570
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) < 960
GROUP BY d
),
averaged AS
(
SELECT
d,
px,
avg(px) OVER (ORDER BY d ROWS BETWEEN 19 PRECEDING AND CURRENT ROW) AS fast_ma,
avg(px) OVER (ORDER BY d ROWS BETWEEN 49 PRECEDING AND CURRENT ROW) AS slow_ma,
row_number() OVER (ORDER BY d) AS session_no
FROM daily
),
positioned AS
(
SELECT
d,
px,
if(session_no >= 50 AND fast_ma > slow_ma, 1, 0) AS long_today,
lagInFrame(if(session_no >= 50 AND fast_ma > slow_ma, 1, 0), 1)
OVER (ORDER BY d ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS long_prior,
lagInFrame(px, 1)
OVER (ORDER BY d ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS px_prior
FROM averaged
)
SELECT
toYear(d) AS year,
round((exp(sum(log(if(long_prior = 1, px / px_prior, 1.0)))) - 1) * 100, 1) AS next_bar_pct,
round((exp(sum(log(if(long_today = 1, px / px_prior, 1.0)))) - 1) * 100, 1) AS same_bar_pct,
round(abs(exp(sum(log(if(long_today = 1, px / px_prior, 1.0))))
- exp(sum(log(if(long_prior = 1, px / px_prior, 1.0))))) * 100, 1) AS gap_pp
FROM positioned
WHERE px_prior > 0
AND toYear(d) >= 2017
GROUP BY year
ORDER BY yearKatika 2017 toleo la kipindi kilichopita lilichapisha 16% wakati toleo la kipindi hichohicho lilichapisha 17.1%, zikiwa na tofauti ya 1.1 percentage points. Katika 2025 umbali kati ya hizo mbili ulipimwa kuwa 1.6 percentage points. Ni safu wima moja tu kati ya hizo inayoweza kuzalishwa na mashine ambayo haikujua mapema bei ya kufunga ya kipindi hicho, na tofauti kati yao ni uhasibu mtupu, bila wazo, bila ujuzi, na bila biashara yoyote iliyofanyika.
Injini hii inaeleza msimamo wake kuhusu swali la muda, ambao una thamani zaidi kuliko ahadi:
Kwa utekelezaji wa oda wakati wa ufunguzi (at the open), slippage inayozingatia masafa huona tu bar iliyokamilika iliyotangulia na uwezo wa ujazo (volume capacity) hutabiriwa kutoka kwa uchunguzi uliocheleweshwa; injini haitumii bei ya juu, ya chini, ya kufunga au ujazo kamili wa siku hiyo.
Chanzo: quantjourney-bt README, toleo la 0.12.4, iliyosomwa tarehe 6 Agosti 2026.
Dhana iliyoandikwa inaweza kukaguliwa dhidi ya chanzo ulichokwisha sakinisha. Dhana isiyoandikwa ni kubahatisha tu.
Kwa nini nyongeza ya walk-forward ipo
Mifano ya walk-forward, kuanzia WF01 hadi WF05, inakuja na nyongeza ya [wf] pamoja na utegemezi wake wa Optuna. Walk-forward hupanga vigezo (parameters) kwenye kipindi kimoja cha historia, huvipima kwenye kipindi kinachofuata, kisha husogeza jozi hiyo mbele na kurudia mchakato. Tofauti kati ya mbinu za rolling na expanding ni kama dirisha la upangaji linaacha data zake za zamani kadiri linavyosonga mbele. Mfano mwingine huongeza mbinu ya purge na embargo katika kila mpaka, kwa kuondoa data zilizo karibu zaidi na mshono huo, ili kipindi kilichopangwa kisiweze kuvujisha taarifa kwenye kipindi kinachopimwa.
Hakuna hata moja kati ya hayo linalobadilisha wazo dhaifu kuwa wazo linalofanya kazi. Badala yake, inachukua namba moja na kuibadilisha kuwa mgawanyo wa namba ambazo unaweza kuzijadili, na huo ndio uboreshaji wenyewe. Hatua inayofuata bado si matumizi ya fedha halisi: paper trading kabla ya kutumia fedha halisi hupima kile ambacho backtest haiwezi kukiona kimuundo, kuanzia kama oda yako inatekelezwa karibu na bei iliyodhaniwa na simulator, na circuit breakers kwa ajili ya roboti za biashara hushughulikia kile ambacho programu yako hufanya katika siku ambayo haifanyi kazi. Kwa takwimu zilizopo chini ya yote hayo, maelezo yetu kuhusu kitabu cha quant trading cha open-source huenda ndani zaidi.
Maswali Yanayoulizwa Mara kwa Mara
Je, ninaweza kufanya backtest ya mkakati bila API key?
Ndiyo. quantjourney-bt inakuja na mkusanyiko wa data za sampuli kupitia flag ya --sample-data, na mikakati yake ya mfano inaweza kufanya kazi bila akaunti au vitambulisho vyovyote. Mkusanyiko huu wa data ni mdogo na wa kielelezo tu, hivyo chukulia jaribio hilo kama njia ya kuhakiki usakinishaji na mtiririko wa kazi badala ya kulichukulia kama ushahidi wa utendaji wa mkakati.
Kwa nini ni muhimu kufunga (pin) toleo la kifurushi cha Python cha backtesting?
Kifurushi kilicho katika toleo la 0.x hakitoi hakikisho la utangamano kati ya matoleo madogo (minor releases), na mabadiliko ya thamani chaguo-msingi au kubadilishwa kwa jina la kipimo (metric) hakutatoa taarifa yoyote. Kufunga toleo kwa kutumia pip install quantjourney-bt==0.12.4 na kurekodi mazingira ya kazi katika faili ya mahitaji (requirements file) kunamaanisha kuwa matokeo unayopata leo yanaweza kuzalishwa upya mwaka ujao kwa kutumia injini ileile iliyoyazalisha.
quantjourney-bt inatolewa chini ya leseni gani?
Apache License 2.0. Leseni hii inaruhusu matumizi ya kibiashara na marekebisho, inataka uhifadhi faili za leseni na notisi pamoja na usambazaji wowote, na inajumuisha idhini ya wazi ya hataza kutoka kwa wachangiaji. Toleo la 0.12.4 lilichapishwa tarehe ishirini na moja Julai 2026 na linahitaji Python 3.11 au toleo jipya zaidi.
Je, matokeo mazuri ya backtest yanamaanisha kuwa mkakati unafanya kazi?
Hapana. Backtest ni kipimo kimoja, katika kipindi kimoja, kwenye ulimwengu mmoja wa data. Paneli zilizo hapo juu zinaonyesha kanuni moja isiyobadilika ikitoa takwimu tofauti sana za kila mwaka kwenye ticker moja, na takwimu tofauti sana kwenye majina matano, jambo ambalo ndilo pengo ambalo uthibitishaji wa walk-forward na upimaji wa out-of-sample umeundwa ili kulibainisha.
Jinsi paneli zilizo hapo juu zilivyokokotolewa
Bei za kufunga za kila siku (daily closes) ni zile za dakika ya mwisho ya kipindi cha kawaida cha biashara kwa kila tarehe, zikichukuliwa kwa saa za New York kati ya saa tatu na nusu asubuhi na saa kumi jioni, jambo ambalo linahakikisha siku za kufunga mapema zinabaki sahihi bila kuhitaji kuweka urefu wa kipindi kwa mikono. Wastani wa haraka (fast average) unashughulikia vipindi ishirini na wastani wa polepole (slow average) vipindi hamsini, vyote vikiwa ni wastani rahisi, na vipindi arobaini na tisa vya kwanza vya kila mfululizo ni vya maandalizi ambapo hakuna nafasi (position) inayoshikiliwa. Takwimu za kila mwaka zinajumlisha mabadiliko ya bei ya kila kipindi kwa vipindi ambavyo kanuni ilikuwa katika nafasi ya long, na safu ya hold inajumlisha kila kipindi katika mwaka uleule kwa ajili ya kulinganisha. Majina matano yaliyopo kwenye cross-section yalichaguliwa kwa sababu ya historia zao endelevu bila mgawanyo (split) ndani ya kipindi hicho, hivyo mfululizo wa bei za kufunga hauhitaji marekebisho. Vipindi vimefungwa katika wakati uliopita, hivyo paneli hizi hurejesha namba zilezile kila zinapozalishwa upya.
Kila paneli hapa ina SQL kamili iliyo chini yake, jambo linalofanya namba kwenye ukurasa huu ziweze kuendeshwa upya kama ilivyo kwa usakinishaji uliopangwa (pinned install). Ili kupima kanuni katika kipindi chako mwenyewe kabla ya kuandika msimbo wowote wa backtest, uliza swali hilo kwa lugha rahisi kwenye terminal ya Strasmore.