Tarihe odaklı döviz kuru okuma işlemi için basit bir geriye sayım yapabilirsiniz.
Kendi kütüphanemden komple bir fonksiyon paylaşayım.
Dilersem koda odaklı dilersem tüm veriyi okuyabileceğim bir Type dizisi içerecek şekilde Merkez Bankası döviz kurlarını aşağıdaki şekilde alıp kullanıyorum.
@
cinarbil tahmin ettiğiniz şekilde gün gün geri giderek ulaşabildiğim ilk tarihe odaklıyorum.
Tabi bu sınırsız olamaz deyip, (10) gün ile sınırlandırdım. Olası merkez bankası kaynaklı teknik sorun olursa diye ...
uses Xml.XMLIntf, Xml.XMLDoc,
System.Net.HttpClientComponent,
System.DateUtils,
System.UITypes;
{$region ' -- Type Definition Section -- '}
type
tCurrencyDetail = record
CurrencyCode,
Unit_,
Isim,
CurrencyName,
ForexBuying,
ForexSelling,
BanknoteBuying,
BanknoteSelling,
CrossRateUSD,
CrossRateOther: string;
end;
tCurrencyDetails = array of tCurrencyDetail;
tCurrencyInfo = record
Tarih,
Date,
Bulten_No : string;
CurrencyList : tCurrencyDetails;
CurrIdx : Integer;
// Debug edilmek istenirse kaynak veri
SourceUrl : string;
SourceXML : string;
end;
{$endregion ' -- Type Definition Section -- '}
function MerkezBankasi_KurVerisi( aCurrencyCode: string; aDate: TDateTime ): tCurrencyInfo;
// https://www.tcmb.gov.tr/kurlar/202401/05012024.xml
var
LCurrInfo : tCurrencyInfo;
LCurrList : tCurrencyDetails;
{$region ' -- Currency Parse Section -- '}
procedure ParseCurrCodes(aContent:String);
function ParseSubValue( aCurrencyContent:string ): tCurrencyDetail;
var
LSubXMLDocument : IXMLDocument;
LSubRootNode : IXMLNode;
LSubNode : IXMLNode;
begin
result := default(tCurrencyDetail);
LSubXMLDocument := TXMLDocument.Create(nil);
try
LSubXMLDocument.ParseOptions := LSubXMLDocument.ParseOptions+[poPreserveWhiteSpace];
LSubXMLDocument.XML.Clear;
LSubXMLDocument.XML.Text := aCurrencyContent;
LSubXMLDocument.Active := TRUE;
if ( LSubXMLDocument <> nil )
and ( LSubXMLDocument.ChildNodes.Count > 0 )
then
LSubRootNode := LSubXMLDocument.ChildNodes.First;
if ( LSubRootNode <> nil )
and ( LSubRootNode.HasChildNodes )
then
LSubNode := LSubRootNode.ChildNodes.First;
while (LSubNode <> nil)
and (LSubNode.NodeType = ntText)
do
LSubNode := LSubNode.NextSibling;
if LSubNode <> nil then
begin
while (LSubNode <> nil) do
begin
if ( LSubNode.NodeType <> ntText )
and ( NOT VarIsNull( LSubNode.NodeValue ) )
then
begin
if LSubNode.NodeName = 'Unit' then result.Unit_ := LSubNode.NodeValue;
if LSubNode.NodeName = 'Isim' then result.Isim := LSubNode.NodeValue;
if LSubNode.NodeName = 'CurrencyName' then result.CurrencyName := LSubNode.NodeValue;
if LSubNode.NodeName = 'ForexBuying' then result.ForexBuying := LSubNode.NodeValue;
if LSubNode.NodeName = 'ForexSelling' then result.ForexSelling := LSubNode.NodeValue;
if LSubNode.NodeName = 'BanknoteBuying' then result.BanknoteBuying := LSubNode.NodeValue;
if LSubNode.NodeName = 'BanknoteSelling' then result.BanknoteSelling := LSubNode.NodeValue;
if LSubNode.NodeName = 'CrossRateUSD' then result.CrossRateUSD := LSubNode.NodeValue;
if LSubNode.NodeName = 'CrossRateOther' then result.CrossRateOther := LSubNode.NodeValue;
end;
LSubNode := LSubNode.NextSibling;
end;
end;
except
on E: Exception do
raise Exception.Create( E.ClassName + ':' + E.Message );
end;
end;
var
LXMLDocument : IXMLDocument;
LRootNode : IXMLNode;
LNode : IXMLNode;
LCurrencyCode : IXMLNode;
begin
Finalize(LCurrList);
LXMLDocument := TXMLDocument.Create(nil);
try
LXMLDocument.ParseOptions := LXMLDocument.ParseOptions+[poPreserveWhiteSpace];
LXMLDocument.XML.Clear;
LXMLDocument.XML.Text := aContent;
LXMLDocument.Active := TRUE;
if ( LXMLDocument <> nil )
and ( LXMLDocument.ChildNodes.Count > 0 )
then
LRootNode := LXMLDocument.ChildNodes.First;
while ( LRootNode <> nil )
and ( LRootNode.NodeName <> 'Tarih_Date' )
do
LRootNode := LRootNode.NextSibling;
if ( LRootNode <> nil )
and ( LRootNode.HasChildNodes ) then
begin
LCurrInfo := default( tCurrencyInfo );
LCurrInfo.CurrIdx := -1; // not assigned
if LRootNode.AttributeNodes.FindNode('Tarih') <> nil
then LCurrInfo.Tarih := LRootNode.AttributeNodes.FindNode('Tarih').NodeValue;
if LRootNode.AttributeNodes.FindNode('Date') <> nil
then LCurrInfo.Date := LRootNode.AttributeNodes.FindNode('Date').NodeValue;
if LRootNode.AttributeNodes.FindNode('Bulten_No') <> nil
then LCurrInfo.Bulten_No := LRootNode.AttributeNodes.FindNode('Bulten_No').NodeValue;
LNode := LRootNode.ChildNodes.First;
end;
while (LNode <> nil)
and (LNode.NodeType = ntText)
do
LNode := LNode.NextSibling;
if LNode <> nil then
begin
while (LNode <> nil) do
begin
if ('Currency' = LNode.NodeName )
then
begin
LCurrencyCode := LNode.AttributeNodes.FindNode('CurrencyCode');
if ( LCurrencyCode <> nil )
and ( LCurrencyCode.NodeType = ntAttribute )
then begin
SetLength(LCurrList, length(LCurrList)+1);
LCurrList[high(LCurrList)] := ParseSubValue( LNode.XML );
LCurrList[high(LCurrList)].CurrencyCode := LCurrencyCode.NodeValue;
end;
end;
LNode := LNode.NextSibling;
end;
end;
except
on E: Exception do
raise Exception.Create( E.ClassName + ':' + E.Message );
end;
end;
{$endregion ' -- Currency Parse Section -- '}
const
LBaseUrl = 'https://www.tcmb.gov.tr/kurlar';
var
LClient : System.Net.HttpClientComponent.TNetHTTPClient;
LUrl : string;
LResponse : TStringStream;
LDate : TDateTime;
LTrial,
LStatus : Integer;
i : Integer;
LProc : String;
begin
LProc := '[MerkezBankasi_CrossRateUSD] ';
LResponse := TStringStream.Create;
LClient := TNetHTTPClient.Create(nil);
try
LClient.UserAgent := 'Mozilla/5.0';
try
LTrial := 0;
LStatus := 0;
LDate := aDate;
while ( LStatus <> 200 ) and ( LTrial < 10 ) do
begin
inc(LTrial); // max 10 gün önceye kadar tekrarla..
LUrl := Format( '%s/%s.xml', [LBaseUrl, FormatDateTime('YYYYMM"/"DDMMYYYY', LDate) ] );
LStatus := LClient.Get( LUrl, LResponse ).StatusCode;
if LStatus = 200 then
begin
//Parse to LCurrList
ParseCurrCodes(LResponse.DataString);
LCurrInfo.CurrencyList := LCurrList;
Result := LCurrInfo;
// Debug edilmek istenirse kaynak veri...
Result.SourceUrl := LUrl;
Result.SourceXML := LResponse.DataString;
for i := Low(LCurrList) to High(LCurrList) do
begin
if LCurrList[i].CurrencyCode = aCurrencyCode then
begin
Result.CurrIdx := i;
break;
end;
end;
end else
begin
LDate := IncDay( LDate, -1 ); // Haftasonu veya bayram olabilir
// bir gün öncesi ile yeniden...
Result := default(tCurrencyInfo);
Result.CurrIdx := -1; // not assigned
end;
end;
except on E: Exception do
begin
// Burada VCL ise mesaj verdirebilir, service ise Debug Dump yapabilirsiniz.
MessageDlg( format('%s'+sLineBreak+'%s', [
'Döviz kuru için Merkez Bankası bağlantısı sağlanamadı...', E.Message ])
, TMsgDlgType.mtError, [mbCancel], 0 );
Result := default(tCurrencyInfo);
Result.CurrIdx := -1; // not assigned
end;
end;
finally
FreeAndNil(LClient);
FreeAndNil(LResponse);
end;
end;
Kullanımı :
procedure TForm1.BitBtn1Click(Sender: TObject);
var
KurBilgisi : tCurrencyInfo;
begin
KurBilgisi := MerkezBankasi_KurVerisi( 'USD', now);
if KurBilgisi.CurrIdx > -1 then
begin
ShowmessageFmt( '%s %s : %s'+sLineBreak+'%s' + sLineBreak + 'Döv.Al: %s Döv.Sat: %s',
[
KurBilgisi.Tarih,
KurBilgisi.Bulten_No,
KurBilgisi.CurrencyList[KurBilgisi.CurrIdx].CurrencyName,
KurBilgisi.CurrencyList[KurBilgisi.CurrIdx].CurrencyCode,
KurBilgisi.CurrencyList[KurBilgisi.CurrIdx].ForexBuying,
KurBilgisi.CurrencyList[KurBilgisi.CurrIdx].ForexSelling
] );
end;
end;