//--- 거래를 저장할 구조
struct Deal
{
ulong ticket; // DEAL_TICKET
long order_ticket; // DEAL_ORDER
long position_ticket; // DEAL_POSITION_ID
datetime time; // DEAL_TIME
char type; // DEAL_TYPE
char entry; // DEAL_ENTRY
string symbol; // DEAL_SYMBOL
double volume; // DEAL_VOLUME
double price; // DEAL_PRICE
double profit; // DEAL_PROFIT
double swap; // DEAL_SWAP
double commission; // DEAL_COMMISSION
long magic; // DEAL_MAGIC
char reason; // DEAL_REASON
};
//--- 거래 저장 구조: 회원의 주문은 터미널 내 포지션에 해당
struct Trade
{
datetime time_in; // 진입 시간
ulong ticket; // 포지션 ID
char type; // 구매 또는 판매
double volume; // 볼륨
string symbol; // 심볼
double price_in; // 진입 가격
datetime time_out; // 퇴장 시간
double price_out; // 퇴장 가격
double commission; // 진입 및 퇴장 수수료
double swap; // 스왑
double profit; // 수익 또는 손실
};
//+------------------------------------------------------------------+
//| 스크립트 프로그램 시작 기능 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 파일 이름 생성
string filename=IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN))+"_trades.sqlite";
//--- 공용 터미널 폴더에서 데이터베이스 열기/생성
int db=DatabaseOpen(filename, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE | DATABASE_OPEN_COMMON);
if(db==INVALID_HANDLE)
{
Print("DB: ", filename, " 코드와 함께 열기 실패 ", GetLastError());
return;
}
//--- DEALS 표를 작성
if(!CreateTableDeals(db))
{
DatabaseClose(db);
return;
}
//--- 전체 트레이딩 내역을 요청
datetime from_date=0;
datetime to_date=TimeCurrent();
//--- 거래 내역을 지정 간격 내에 요청
HistorySelect(from_date, to_date);
int deals_total=HistoryDealsTotal();
PrintFormat("트레이딩 내역 내 거래: %d ", deals_total);
//--- 표에 거래 추가
if(!InsertDeals(db))
return;
//--- 첫 10개 거래 표시
Deal deals[], deal;
ArrayResize(deals, 10);
int request=DatabasePrepare(db, "SELECT * FROM DEALS");
if(request==INVALID_HANDLE)
{
Print("DB: ", filename, " 코드를 이용한 요청 실패 ", GetLastError());
DatabaseClose(db);
return;
}
int i;
for(i=0; DatabaseReadBind(request, deal); i++)
{
if(i>=10)
break;
deals[i].ticket=deal.ticket;
deals[i].order_ticket=deal.order_ticket;
deals[i].position_ticket=deal.position_ticket;
deals[i].time=deal.time;
deals[i].type=deal.type;
deals[i].entry=deal.entry;
deals[i].symbol=deal.symbol;
deals[i].volume=deal.volume;
deals[i].price=deal.price;
deals[i].profit=deal.profit;
deals[i].swap=deal.swap;
deals[i].commission=deal.commission;
deals[i].magic=deal.magic;
deals[i].reason=deal.reason;
}
//--- 거래 출력
if(i>0)
{
ArrayResize(deals, i);
PrintFormat("첫 %d 거래:", i);
ArrayPrint(deals);
}
//--- 사용 후 요청 삭제
DatabaseFinalize(request);
//--- 오픈 포지션 관리를 위한 헤징 시스템을 계좌에서 사용하는지 확인
if((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
{
//--- 거래를 트랜잭션을 통한 단순한 방법을 사용하여 트레이딩으로 전환할 수 없으므로 완전한 운영이 가능합니다
DatabaseClose(db);
return;
}
//--- 이제 DEALS 표를 기반으로 TRADES 표를 작성
if(!CreateTableTrades(db))
{
DatabaseClose(db);
return;
}
//--- DEALS 표 데이터를 기반으로 SQL 쿼리를 사용하여 TRADES 표를 채우기
ulong start=GetMicrosecondCount();
if(DatabaseTableExists(db, "DEALS"))
//--- TRADES 표 덧붙이기
if(!DatabaseExecute(db, "INSERT INTO TRADES(TIME_IN,TICKET,TYPE,VOLUME,SYMBOL,PRICE_IN,TIME_OUT,PRICE_OUT,COMMISSION,SWAP,PROFIT) "
"SELECT "
" d1.time as time_in,"
" d1.position_id as ticket,"
" d1.type as type,"
" d1.volume as volume,"
" d1.symbol as symbol,"
" d1.price as price_in,"
" d2.time as time_out,"
" d2.price as price_out,"
" d1.commission+d2.commission as commission,"
" d2.swap as swap,"
" d2.profit as profit "
"FROM DEALS d1 "
"INNER JOIN DEALS d2 ON d1.position_id=d2.position_id "
"WHERE d1.entry=0 AND d2.entry=1 "))
{
Print("DB: 코드로 TRADES 표를 채우는데 실패 ", GetLastError());
return;
}
ulong transaction_time=GetMicrosecondCount()-start;
//--- 첫 10개 거래 표시
Trade trades[], trade;
ArrayResize(trades, 10);
request=DatabasePrepare(db, "SELECT * FROM TRADES");
if(request==INVALID_HANDLE)
{
Print("DB: ", filename, " 코드를 이용한 요청 실패 ", GetLastError());
DatabaseClose(db);
return;
}
for(i=0; DatabaseReadBind(request, trade); i++)
{
if(i>=10)
break;
trades[i].time_in=trade.time_in;
trades[i].ticket=trade.ticket;
trades[i].type=trade.type;
trades[i].volume=trade.volume;
trades[i].symbol=trade.symbol;
trades[i].price_in=trade.price_in;
trades[i].time_out=trade.time_out;
trades[i].price_out=trade.price_out;
trades[i].commission=trade.commission;
trades[i].swap=trade.swap;
trades[i].profit=trade.profit;
}
//--- 거래 인쇄
if(i>0)
{
ArrayResize(trades, i);
PrintFormat("\r\nThe first %d trades:", i);
ArrayPrint(trades);
PrintFormat("TRADES 표를 채우는 데 %.2f 밀리초가 걸렸습니다",double(transaction_time)/1000);
}
//--- 사용 후 요청 삭제
DatabaseFinalize(request);
//--- 데이터베이스 닫기
DatabaseClose(db);
}
/*
Results:
Deals in the trading history: 2741
The first 10 deals:
[ticket] [order_ticket] [position_ticket] [time] [type] [entry] [symbol] [volume] [price] [profit] [swap] [commission] [magic] [reason]
[0] 34429573 0 0 2019.09.05 22:39:59 2 0 "" 0.00000 0.00000 2000.00000 0.0000 0.00000 0 0
[1] 34432127 51447238 51447238 2019.09.06 06:00:03 0 0 "USDCAD" 0.10000 1.32320 0.00000 0.0000 -0.16000 500 3
[2] 34432128 51447239 51447239 2019.09.06 06:00:03 1 0 "USDCHF" 0.10000 0.98697 0.00000 0.0000 -0.16000 500 3
[3] 34432450 51447565 51447565 2019.09.06 07:00:00 0 0 "EURUSD" 0.10000 1.10348 0.00000 0.0000 -0.18000 400 3
[4] 34432456 51447571 51447571 2019.09.06 07:00:00 1 0 "AUDUSD" 0.10000 0.68203 0.00000 0.0000 -0.11000 400 3
[5] 34432879 51448053 51448053 2019.09.06 08:00:00 1 0 "USDCHF" 0.10000 0.98701 0.00000 0.0000 -0.16000 600 3
[6] 34432888 51448064 51448064 2019.09.06 08:00:00 0 0 "USDJPY" 0.10000 106.96200 0.00000 0.0000 -0.16000 600 3
[7] 34435147 51450470 51450470 2019.09.06 10:30:00 1 0 "EURUSD" 0.10000 1.10399 0.00000 0.0000 -0.18000 100 3
[8] 34435152 51450476 51450476 2019.09.06 10:30:00 0 0 "GBPUSD" 0.10000 1.23038 0.00000 0.0000 -0.20000 100 3
[9] 34435154 51450479 51450479 2019.09.06 10:30:00 1 0 "EURJPY" 0.10000 118.12000 0.00000 0.0000 -0.18000 200 3
The first 10 trades:
[time_in] [ticket] [type] [volume] [symbol] [price_in] [time_out] [price_out] [commission] [swap] [profit]
[0] 2019.09.06 06:00:03 51447238 0 0.10000 "USDCAD" 1.32320 2019.09.06 18:00:00 1.31761 -0.32000 0.00000 -42.43000
[1] 2019.09.06 06:00:03 51447239 1 0.10000 "USDCHF" 0.98697 2019.09.06 18:00:00 0.98641 -0.32000 0.00000 5.68000
[2] 2019.09.06 07:00:00 51447565 0 0.10000 "EURUSD" 1.10348 2019.09.09 03:30:00 1.10217 -0.36000 -1.31000 -13.10000
[3] 2019.09.06 07:00:00 51447571 1 0.10000 "AUDUSD" 0.68203 2019.09.09 03:30:00 0.68419 -0.22000 0.03000 -21.60000
[4] 2019.09.06 08:00:00 51448053 1 0.10000 "USDCHF" 0.98701 2019.09.06 18:00:01 0.98640 -0.32000 0.00000 6.18000
[5] 2019.09.06 08:00:00 51448064 0 0.10000 "USDJPY" 106.96200 2019.09.06 18:00:01 106.77000 -0.32000 0.00000 -17.98000
[6] 2019.09.06 10:30:00 51450470 1 0.10000 "EURUSD" 1.10399 2019.09.06 14:30:00 1.10242 -0.36000 0.00000 15.70000
[7] 2019.09.06 10:30:00 51450476 0 0.10000 "GBPUSD" 1.23038 2019.09.06 14:30:00 1.23040 -0.40000 0.00000 0.20000
[8] 2019.09.06 10:30:00 51450479 1 0.10000 "EURJPY" 118.12000 2019.09.06 14:30:00 117.94100 -0.36000 0.00000 16.73000
[9] 2019.09.06 10:30:00 51450480 0 0.10000 "GBPJPY" 131.65300 2019.09.06 14:30:01 131.62500 -0.40000 0.00000 -2.62000
Filling the TRADES table took 12.51 milliseconds
*/
//+------------------------------------------------------------------+
//| DEALS 표 생성 |
//+------------------------------------------------------------------+
bool CreateTableDeals(int database)
{
//--- DEALS 표가 이미 있는 경우 삭제
if(!DeleteTable(database, "DEALS"))
{
return(false);
}
//--- 표의 존재유무 확인
if(!DatabaseTableExists(database, "DEALS"))
//--- 표 생성
if(!DatabaseExecute(database, "CREATE TABLE DEALS("
"ID INT KEY NOT NULL,"
"ORDER_ID INT NOT NULL,"
"POSITION_ID INT NOT NULL,"
"TIME INT NOT NULL,"
"TYPE INT NOT NULL,"
"ENTRY INT NOT NULL,"
"SYMBOL CHAR(10),"
"VOLUME REAL,"
"PRICE REAL,"
"PROFIT REAL,"
"SWAP REAL,"
"COMMISSION REAL,"
"MAGIC INT,"
"REASON INT );"))
{
Print("DB: 코드로 DEALS 표를 생성하는데 실패 ", GetLastError());
return(false);
}
//--- 표가 성공적으로 생성되었습니다
return(true);
}
//+------------------------------------------------------------------+
//| 데이터베이스에서 지정된 이름의 표를 삭제 |
//+------------------------------------------------------------------+
bool DeleteTable(int database, string table_name)
{
if(!DatabaseExecute(database, "DROP TABLE IF EXISTS "+table_name))
{
Print("Failed to drop the DEALS table with code ", GetLastError());
return(false);
}
//--- 테이블이 성공적으로 삭제되었습니다
return(true);
}
//+------------------------------------------------------------------+
//| 데이터베이스 표에 거래 추가 |
//+------------------------------------------------------------------+
bool InsertDeals(int database)
{
//--- 보조 변수
ulong deal_ticket; // 거래 티켓
long order_ticket; // 거래가 실행된 주문 티켓
long position_ticket; // 거래가 속한 포지션의 ID
datetime time; // 거래 실행 시간
long type ; // 거래 유형
long entry ; // 거래 방향
string symbol; // 거래가 실행된 심볼
double volume; // 작업 볼륨
double price; // 가격
double profit; // 재정적 결과
double swap; // 스왑
double commission; // 수수료
long magic; // 매직 넘버 (엑스퍼트 어드바이저 ID)
long reason; // 거래 실행 이유 또는 소스
//--- 모든 거래를 검토하여 데이터 베이스에 추가
bool failed=false;
int deals=HistoryDealsTotal();
// --- 트랜잭션을 실행하기 전에 데이터베이스를 잠금
DatabaseTransactionBegin(database);
for(int i=0; i<deals; i++)
{
deal_ticket= HistoryDealGetTicket(i);
order_ticket= HistoryDealGetInteger(deal_ticket, DEAL_ORDER);
position_ticket=HistoryDealGetInteger(deal_ticket, DEAL_POSITION_ID);
time= (datetime)HistoryDealGetInteger(deal_ticket, DEAL_TIME);
type= HistoryDealGetInteger(deal_ticket, DEAL_TYPE);
entry= HistoryDealGetInteger(deal_ticket, DEAL_ENTRY);
symbol= HistoryDealGetString(deal_ticket, DEAL_SYMBOL);
volume= HistoryDealGetDouble(deal_ticket, DEAL_VOLUME);
price= HistoryDealGetDouble(deal_ticket, DEAL_PRICE);
profit= HistoryDealGetDouble(deal_ticket, DEAL_PROFIT);
swap= HistoryDealGetDouble(deal_ticket, DEAL_SWAP);
commission= HistoryDealGetDouble(deal_ticket, DEAL_COMMISSION);
magic= HistoryDealGetInteger(deal_ticket, DEAL_MAGIC);
reason= HistoryDealGetInteger(deal_ticket, DEAL_REASON);
//--- 다음 요청에 따라 각 거래를 표에 추가
string request_text=StringFormat("INSERT INTO DEALS (ID,ORDER_ID,POSITION_ID,TIME,TYPE,ENTRY,SYMBOL,VOLUME,PRICE,PROFIT,SWAP,COMMISSION,MAGIC,REASON)"
"VALUES (%d, %d, %d, %d, %d, %d, '%s', %G, %G, %G, %G, %G, %d, %d)",
deal_ticket, order_ticket, position_ticket, time, type, entry, symbol, volume, price, profit, swap, commission, magic, reason);
if(!DatabaseExecute(database, request_text))
{
PrintFormat("%s: %d 코드로 #%d 거래 삽입하는데 실패", __FUNCTION__, deal_ticket, GetLastError());
PrintFormat("i=%d: 거래 #%d %s", i, deal_ticket, symbol);
failed=true;
break;
}
}
//--- 트랜잭션 실행 오류를 확인
if(failed)
{
//--- 모든 트랜잭션 롤백 및 데이터베이스 잠금 해제
DatabaseTransactionRollback(database);
PrintFormat("%s: %d 코드로 DatabaseExecute() 실패", __FUNCTION__, GetLastError());
return(false);
}
//--- 모든 트랜잭션이 성공적으로 수행됨 - 변경 사항을 기록하고 데이터베이스 잠금을 해제합니다
DatabaseTransactionCommit(database);
return(true);
}
//+------------------------------------------------------------------+
//| TRADES 표를 생성 |
//+------------------------------------------------------------------+
bool CreateTableTrades(int database)
{
//--- TRADES 표가 이미 있는 경우 삭제
if(!DeleteTable(database, "TRADES"))
return(false);
//--- 표의 존재유무 확인
if(!DatabaseTableExists(database, "TRADES"))
//--- 표 생성
if(!DatabaseExecute(database, "CREATE TABLE TRADES("
"TIME_IN INT NOT NULL,"
"TICKET INT NOT NULL,"
"TYPE INT NOT NULL,"
"VOLUME REAL,"
"SYMBOL CHAR(10),"
"PRICE_IN REAL,"
"TIME_OUT INT NOT NULL,"
"PRICE_OUT REAL,"
"COMMISSION REAL,"
"SWAP REAL,"
"PROFIT REAL);"))
{
Print("DB: 코드로 TRADES 표를 생성하는데 실패 ", GetLastError());
return(false);
}
//--- 표가 성공적으로 생성되었습니다
return(true);
}
//+------------------------------------------------------------------+
|