Strategy.cpp
上传用户:zhanglf88
上传日期:2013-11-19
资源大小:6036k
文件大小:64k
源码类别:

金融证券系统

开发平台:

Visual C++

  1. /*
  2. Cross Platform Core Code.
  3. Copyright(R) 2001-2002 Balang Software.
  4. All rights reserved.
  5. Using:
  6. class CRateParam;
  7. class COpParam;
  8. class CStockOwnContainer;
  9. class COpRecordContainer;
  10. class CAssetSerialContainer;
  11. class CTechStock;
  12. class CTechStockContainer;
  13. class CStrategy;
  14. */
  15. #include "stdafx.h"
  16. #include "../Include/Strategy.h"
  17. #ifdef _DEBUG
  18. #define new DEBUG_NEW
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22. /////////////////////////////////////////////////////////////////////////////
  23. // CRateParam
  24. CRateParam::CRateParam( )
  25. {
  26. SetDefault( );
  27. }
  28. // 交易费用参数是否合法
  29. BOOL CRateParam::IsValid( )
  30. {
  31. return (m_dShaa >= 0 && m_dShaa < 0.1
  32. && m_dShab >= 0 && m_dShab < 0.1
  33. && m_dShafund >= 0 && m_dShafund < 0.1
  34. && m_dSzna >= 0 && m_dSzna < 0.1
  35. && m_dSznb >= 0 && m_dSznb < 0.1
  36. && m_dSznfund >= 0 && m_dSznfund < 0.1 );
  37. }
  38. // 缺省交易费用
  39. void CRateParam::SetDefault( )
  40. {
  41. m_dShaa = 0.003;
  42. m_dShab = 0.003;
  43. m_dShafund = 0.001;
  44. m_dSzna = 0.003;
  45. m_dSznb = 0.003;
  46. m_dSznfund = 0.001;
  47. }
  48. // 保存交易费用至文件
  49. void CRateParam::Serialize( CSPArchive &ar )
  50. {
  51. if( ar.IsStoring( ) )
  52. {
  53. ar << m_dShaa;
  54. ar << m_dShab;
  55. ar << m_dShafund;
  56. ar << m_dSzna;
  57. ar << m_dSznb;
  58. ar << m_dSznfund;
  59. }
  60. else
  61. {
  62. ar >> m_dShaa;
  63. ar >> m_dShab;
  64. ar >> m_dShafund;
  65. ar >> m_dSzna;
  66. ar >> m_dSznb;
  67. ar >> m_dSznfund;
  68. }
  69. }
  70. // 根据股票选择交易费率
  71. double CRateParam::GetRate( CStockInfo & info )
  72. {
  73. LONG stocktype = info.GetType();
  74. if( CStock::typeshA == stocktype || CStock::typeshIndex == stocktype )
  75. return m_dShaa;
  76. else if( CStock::typeshB == stocktype )
  77. return m_dShab;
  78. else if( info.IsShangHai() && info.IsFund() )
  79. return m_dShafund;
  80. else if( CStock::typeszA == stocktype || CStock::typeszIndex == stocktype )
  81. return m_dSzna;
  82. else if( CStock::typeszB == stocktype )
  83. return m_dSznb;
  84. else if( info.IsShenZhen() && info.IsFund() )
  85. return m_dSznfund;
  86. return 0;
  87. }
  88. /////////////////////////////////////////////////////////////////////////////
  89. // COpParam
  90. // 逻辑字符串,全部指标 任一指标
  91. CSPString AfxGetLogicString( int nLogic )
  92. {
  93. switch( nLogic )
  94. {
  95. case COpParam::logicAnd: return strategy_logicand;
  96. case COpParam::logicOr: return strategy_logicor;
  97. default:
  98. SP_ASSERT( FALSE );
  99. }
  100. return "";
  101. }
  102. // 仓位字符串
  103. CSPString AfxGetStoreDivString( int nStoreDiv )
  104. {
  105. switch( nStoreDiv )
  106. {
  107. case COpParam::storedivOnce: return strategy_sdonce;
  108. case COpParam::storedivTwice: return strategy_sdtwice;
  109. case COpParam::storedivThird: return strategy_sdthird;
  110. case COpParam::storedivForth: return strategy_sdforth;
  111. case COpParam::storedivFifth: return strategy_sdfifth;
  112. case COpParam::storedivSixth: return strategy_sdsixth;
  113. case COpParam::storedivSeventh: return strategy_sdseventh;
  114. case COpParam::storedivEighth: return strategy_sdeighth;
  115. case COpParam::storedivNinth: return strategy_sdninth;
  116. case COpParam::storedivTenth: return strategy_sdtenth;
  117. default:
  118. SP_ASSERT( FALSE );
  119. }
  120. return "";
  121. }
  122. COpParam::COpParam( )
  123. {
  124. SetDefault( );
  125. }
  126. // 操作条件是否合法
  127. BOOL COpParam::IsValid( )
  128. {
  129. if( CKData::ktypeDay != m_nKType && CKData::ktypeWeek != m_nKType && CKData::ktypeMonth != m_nKType )
  130. return FALSE;
  131. if( m_nMaindataType < CKData::mdtypeMin || m_nMaindataType > CKData::mdtypeMax )
  132. return FALSE;
  133. if( m_nBuyLogic < logicMin || m_nBuyLogic > logicMax )
  134. return FALSE;
  135. if( m_nBuyLimit < ITS_MIN || m_nBuyLimit > ITS_MAX )
  136. return FALSE;
  137. if( m_dBuyMulti <= 0.89 || m_dBuyMulti > 1.11 )
  138. return FALSE;
  139. if( m_nSellLogic < logicMin || m_nSellLogic > logicMax )
  140. return FALSE;
  141. if( m_nSellLimit < ITS_MIN || m_nSellLimit > ITS_MAX )
  142. return FALSE;
  143. if( m_dSellMulti <= 0.89 || m_dSellMulti > 1.11 )
  144. return FALSE;
  145. if( m_atmBegin.GetSize() <= 0 || m_atmEnd.GetSize() <= 0
  146. || m_atmBegin.GetSize() != m_atmEnd.GetSize() )
  147. return FALSE;
  148. // TIMEZONES
  149. if( m_nStartAmount < 1000 || m_nStartAmount > 2000000000 )
  150. return FALSE;
  151. if( m_nStoreDiv < storedivMin || m_nStoreDiv > COpParam::storedivMax )
  152. return FALSE;
  153. if( m_bStopLosing && ( m_dStopLosing <= 0 || m_dStopLosing >= 100 ) )
  154. return FALSE;
  155. if( m_bStopProfit && m_dStopProfit <= 0 )
  156. return FALSE;
  157. if( m_bLongTrend && CKData::ktypeDay != m_nKTypeLong && CKData::ktypeWeek != m_nKTypeLong && CKData::ktypeMonth != m_nKTypeLong )
  158. return FALSE;
  159. if( m_bIndexTrend && CKData::ktypeDay != m_nKTypeIndex && CKData::ktypeWeek != m_nKTypeIndex && CKData::ktypeMonth != m_nKTypeIndex )
  160. return FALSE;
  161. return TRUE;
  162. }
  163. // 缺省操作条件
  164. void COpParam::SetDefault( )
  165. {
  166. m_nKType = CKData::ktypeDay;
  167. m_nMaindataType = CKData::mdtypeClose;
  168. m_nBuyLogic = logicAnd;
  169. m_nBuyLimit = ITS_BUY;
  170. m_dBuyMulti = 1.0;
  171. m_nSellLogic = logicOr;
  172. m_nSellLimit = ITS_SELL;
  173. m_dSellMulti = 0.98;
  174. CSPTime tmCurrent = CSPTime::GetCurrentTime();
  175. m_atmBegin.RemoveAll();
  176. m_atmEnd.RemoveAll();
  177. m_atmBegin.Add( tmCurrent - CSPTimeSpan( 365 * 3, 0, 0, 0 ) );
  178. m_atmEnd.Add( tmCurrent );
  179. m_nStartAmount = 1000000;
  180. m_nStoreDiv = storedivThird;
  181. m_bStopLosing = FALSE;
  182. m_bStopProfit = FALSE;
  183. m_dStopLosing = 0.1;
  184. m_dStopProfit = 0.3;
  185. m_bLongTrend = FALSE;
  186. m_bIndexTrend = FALSE;
  187. m_nKTypeLong = CKData::ktypeWeek;
  188. m_nKTypeIndex = CKData::ktypeWeek;
  189. }
  190. // 设定不合法的操作条件为缺省值
  191. void COpParam::SetDefaultOfInvalidMember( )
  192. {
  193. if( CKData::ktypeDay != m_nKType && CKData::ktypeWeek != m_nKType && CKData::ktypeMonth != m_nKType )
  194. m_nKType = CKData::ktypeDay;
  195. if( m_nMaindataType < CKData::mdtypeMin || m_nMaindataType > CKData::mdtypeMax )
  196. m_nMaindataType = CKData::mdtypeClose;
  197. if( m_nBuyLogic < logicMin || m_nBuyLogic > logicMax )
  198. m_nBuyLogic = logicAnd;
  199. if( m_nBuyLimit < ITS_MIN || m_nBuyLimit > ITS_MAX )
  200. m_nBuyLimit = ITS_BUY;
  201. if( m_dBuyMulti <= 0.89 || m_dBuyMulti > 1.11 )
  202. m_dBuyMulti = 1.0;
  203. if( m_nSellLogic < logicMin || m_nSellLogic > logicMax )
  204. m_nSellLogic = logicOr;
  205. if( m_nSellLimit < ITS_MIN || m_nSellLimit > ITS_MAX )
  206. m_nSellLimit = ITS_SELL;
  207. if( m_dSellMulti <= 0.89 || m_dSellMulti > 1.11 )
  208. m_dSellMulti = 0.98;
  209. if( m_atmBegin.GetSize() <= 0 || m_atmEnd.GetSize() <= 0
  210. || m_atmBegin.GetSize() != m_atmEnd.GetSize() )
  211. {
  212. m_atmBegin.RemoveAll();
  213. m_atmEnd.RemoveAll();
  214. CSPTime tmCurrent = CSPTime::GetCurrentTime();
  215. m_atmBegin.Add( tmCurrent - CSPTimeSpan( 365 * 3, 0, 0, 0 ) );
  216. m_atmEnd.Add( tmCurrent );
  217. }
  218. // TIMEZONES
  219. if( m_nStartAmount < 1000 || m_nStartAmount > 2000000000 )
  220. m_nStartAmount = 1000000;
  221. if( m_nStoreDiv < storedivMin || m_nStoreDiv > storedivMax )
  222. m_nStoreDiv = storedivThird;
  223. if( m_bStopLosing && ( m_dStopLosing <= 0 || m_dStopLosing >= 100 ) )
  224. m_dStopLosing = 0.1;
  225. if( m_bStopProfit && m_dStopProfit <= 0 )
  226. m_dStopProfit = 0.3;
  227. if( m_bLongTrend && CKData::ktypeDay != m_nKTypeLong && CKData::ktypeWeek != m_nKTypeLong && CKData::ktypeMonth != m_nKTypeLong )
  228. m_nKTypeLong = CKData::ktypeWeek;
  229. if( m_bIndexTrend && CKData::ktypeDay != m_nKTypeIndex && CKData::ktypeWeek != m_nKTypeIndex && CKData::ktypeMonth != m_nKTypeIndex )
  230. m_nKTypeIndex = CKData::ktypeWeek;
  231. }
  232. // 保存或者读取硬盘文件
  233. void COpParam::Serialize( CSPArchive &ar )
  234. {
  235. if( ar.IsStoring( ) )
  236. {
  237. ar << m_nKType;
  238. ar << m_nMaindataType;
  239. ar << m_nBuyLogic;
  240. ar << m_nBuyLimit;
  241. ar << m_dBuyMulti;
  242. ar << m_nSellLogic;
  243. ar << m_nSellLimit;
  244. ar << m_dSellMulti;
  245. m_atmBegin.Serialize( ar );
  246. m_atmEnd.Serialize( ar );
  247. ar << m_nStartAmount;
  248. ar << m_nStoreDiv;
  249. ar << m_bStopLosing;
  250. ar << m_bStopProfit;
  251. ar << m_dStopLosing;
  252. ar << m_dStopProfit;
  253. ar << m_bLongTrend;
  254. ar << m_bIndexTrend;
  255. ar << m_nKTypeLong;
  256. ar << m_nKTypeIndex;
  257. }
  258. else
  259. {
  260. ar >> m_nKType;
  261. ar >> m_nMaindataType;
  262. ar >> m_nBuyLogic;
  263. ar >> m_nBuyLimit;
  264. ar >> m_dBuyMulti;
  265. ar >> m_nSellLogic;
  266. ar >> m_nSellLimit;
  267. ar >> m_dSellMulti;
  268. m_atmBegin.Serialize( ar );
  269. m_atmEnd.Serialize( ar );
  270. ar >> m_nStartAmount;
  271. ar >> m_nStoreDiv;
  272. ar >> m_bStopLosing;
  273. ar >> m_bStopProfit;
  274. ar >> m_dStopLosing;
  275. ar >> m_dStopProfit;
  276. ar >> m_bLongTrend;
  277. ar >> m_bIndexTrend;
  278. ar >> m_nKTypeLong;
  279. ar >> m_nKTypeIndex;
  280. }
  281. }
  282. // 给定时间是不是在模拟时间内
  283. BOOL COpParam::IsInTimeZones( CSPTime tm )
  284. {
  285. for( int i=0; i<m_atmBegin.GetSize() && i<m_atmEnd.GetSize(); i++ )
  286. {
  287. if( tm >= m_atmBegin.ElementAt(i) && tm <= m_atmEnd.ElementAt(i) )
  288. return TRUE;
  289. }
  290. return FALSE;
  291. }
  292. // 获取模拟开始时间
  293. CSPTime COpParam::GetBeginTime( )
  294. {
  295. if( m_atmBegin.GetSize() > 0 )
  296. return m_atmBegin.ElementAt(0);
  297. return CSPTime::GetCurrentTime();
  298. }
  299. // 获取模拟结束时间
  300. CSPTime COpParam::GetEndTime( )
  301. {
  302. if( m_atmEnd.GetSize() > 0 )
  303. return m_atmEnd.ElementAt(m_atmEnd.GetSize()-1);
  304. return CSPTime::GetCurrentTime();
  305. }
  306. // 获取下一个交易时间
  307. BOOL COpParam::GetNextTradeTime( CSPTime tmNow, CSPTime &tmNext )
  308. {
  309. CSPTime sptime( tmNow.GetTime() );
  310. DWORD dwDate = sptime.ToStockTime( CKData::IsDayOrMin(m_nKType) );
  311. DWORD dwDateNext = CSPTime::GetStockTimeNext( dwDate, m_nKType );
  312. if( sptime.FromStockTime( dwDateNext, CKData::IsDayOrMin(m_nKType) ) )
  313. {
  314. tmNext = sptime.GetTime();
  315. return TRUE;
  316. }
  317. return FALSE;
  318. }
  319. // 获取当前模拟进度
  320. DWORD COpParam::GetProgress( CSPTime tmNow, DWORD dwProgressMax )
  321. {
  322. // TIMEZONES
  323. if( !IsInTimeZones( tmNow ) )
  324. return 0;
  325. CSPTime tmBegin = GetBeginTime( );
  326. CSPTime tmEnd = GetEndTime( );
  327. double dBeginNow = ( tmNow.GetTime() - tmBegin.GetTime() );
  328. double dBeginEnd = ( tmEnd.GetTime() - tmBegin.GetTime() );
  329. double dProgress = 0;
  330. if( fabs(dBeginEnd) > 1e-4 )
  331. {
  332. dProgress = ( dBeginNow / dBeginEnd ) * dwProgressMax;
  333. }
  334. return (DWORD)dProgress;
  335. }
  336. /////////////////////////////////////////////////////////////////////////////
  337. // CStockOwnContainer
  338. // 拥有股票数组,加入股票
  339. BOOL CStockOwnContainer::AddStock( CStockInfo & info, DWORD dwShare, double dBuyPrice )
  340. {
  341. if( dwShare <= 0 )
  342. return FALSE;
  343. // 如果已经有了,改变数量
  344. for( int i=0; i<GetSize(); i++ )
  345. {
  346. STOCKOWN & own = ElementAt(i);
  347. if( info.IsEqualTo( own.dwMarket, own.szCode ) )
  348. {
  349. if( dBuyPrice > 0.005 && own.dwShare + dwShare > 0 )
  350. {
  351. own.dBuyPrice = (own.dBuyPrice * own.dwShare + dBuyPrice * dwShare) / (own.dwShare + dwShare);
  352. }
  353. own.dwShare += dwShare;
  354. return TRUE;
  355. }
  356. }
  357. // 加入新的
  358. STOCKOWN ownnew;
  359. memset( &ownnew, 0, sizeof(ownnew) );
  360. strncpy( ownnew.szCode, info.GetStockCode(), min(sizeof(ownnew.szCode)-1,strlen(info.GetStockCode())) );
  361. ownnew.dwShare = dwShare;
  362. ownnew.dBuyPrice = dBuyPrice;
  363. ownnew.dwMarket = info.GetMarket();
  364. return ( Add(ownnew) >= 0 );
  365. }
  366. // 拥有股票数组,移除股票
  367. BOOL CStockOwnContainer::RemoveStock( CStockInfo & info, DWORD dwShare )
  368. {
  369. for( int i=0; i<GetSize(); i++ )
  370. {
  371. STOCKOWN & own = ElementAt(i);
  372. if( info.IsEqualTo( own.dwMarket, own.szCode ) )
  373. {
  374. if( own.dwShare < dwShare )
  375. return FALSE;
  376. own.dwShare -= dwShare;
  377. if( 0 == own.dwShare )
  378. RemoveAt(i);
  379. return TRUE;
  380. }
  381. }
  382. return FALSE;
  383. }
  384. // 拥有股票数组,是否有这个股票,如果有,返回至lpOwn
  385. BOOL CStockOwnContainer::HasThisStock( CStockInfo & info, LPSTOCKOWN lpOwn )
  386. {
  387. for( int i=0; i<GetSize(); i++ )
  388. {
  389. STOCKOWN & own = ElementAt(i);
  390. if( info.IsEqualTo( own.dwMarket, own.szCode ) )
  391. {
  392. if( lpOwn )
  393. memcpy( lpOwn, &own, sizeof(own) );
  394. return ( own.dwShare > 0 );
  395. }
  396. }
  397. return FALSE;
  398. }
  399. /////////////////////////////////////////////////////////////////////////////
  400. // COpRecordContainer
  401. // 操作描述
  402. CSPString AfxGetStrategyOpTypeString( long lOpType )
  403. {
  404. CSPString strOp;
  405. if( STRATEGY_OPTYPE_BUY == lOpType )
  406. return strategy_optype_buy;
  407. else if( STRATEGY_OPTYPE_SELL == lOpType )
  408. return strategy_optype_sell;
  409. else if( STRATEGY_OPTYPE_ADDSTOCK == lOpType )
  410. return strategy_optype_addstock;
  411. else if( STRATEGY_OPTYPE_REMOVESTOCK == lOpType )
  412. return strategy_optype_removestock;
  413. else if( STRATEGY_OPTYPE_ADDCASH == lOpType )
  414. return strategy_optype_addcash;
  415. else if( STRATEGY_OPTYPE_REMOVECASH == lOpType )
  416. return strategy_optype_removecash;
  417. return strOp;
  418. }
  419. // 操作记录数组,加入记录
  420. int COpRecordContainer::AddRecord(long lOpType, CSPTime tm, const char *szCode,
  421.    DWORD dwShare, double dSharePrice, double dRateCost )
  422. {
  423. SP_ASSERT( NULL != szCode && strlen(szCode) > 0 );
  424. if( NULL == szCode || strlen(szCode) <= 0 )
  425. return -1;
  426. OPRECORD record;
  427. memset( &record, 0, sizeof(record) );
  428. record.lOpType = lOpType;
  429. record.time = tm.GetTime();
  430. strncpy( record.szCode, szCode, min(sizeof(record.szCode)-1,strlen(szCode)) );
  431. record.dwShare = dwShare;
  432. record.dSharePrice = dSharePrice;
  433. record.dRateCost = dRateCost;
  434. record.dwMarket = CStock::marketUnknown;
  435. return Add( record );
  436. }
  437. // 操作记录数组,加入记录,记录中如果已经有该股票的记录,更改为现在的信息
  438. int COpRecordContainer::AddRecordUniqueStock(long lOpType, CSPTime tm, const char *szCode,
  439.    DWORD dwShare, double dSharePrice, double dRateCost )
  440. {
  441. SP_ASSERT( NULL != szCode && strlen(szCode) > 0 );
  442. if( NULL == szCode || strlen(szCode) <= 0 )
  443. return -1;
  444. OPRECORD record;
  445. memset( &record, 0, sizeof(record) );
  446. for( int i=0; i<GetSize(); i++ )
  447. {
  448. if( 0 == strncmp( ElementAt(i).szCode, szCode, sizeof(record.szCode) ) )
  449. {
  450. ElementAt(i).lOpType = lOpType;
  451. ElementAt(i).time = tm.GetTime();
  452. strncpy( ElementAt(i).szCode, szCode, min(sizeof(ElementAt(i).szCode)-1,strlen(szCode)) );
  453. ElementAt(i).dwShare = dwShare;
  454. ElementAt(i).dSharePrice = dSharePrice;
  455. ElementAt(i).dRateCost = dRateCost;
  456. ElementAt(i).dwMarket = CStock::marketUnknown;
  457. return i;
  458. }
  459. }
  460. record.lOpType = lOpType;
  461. record.time = tm.GetTime();
  462. strncpy( record.szCode, szCode, min(sizeof(record.szCode)-1,strlen(szCode)) );
  463. record.dwShare = dwShare;
  464. record.dSharePrice = dSharePrice;
  465. record.dRateCost = dRateCost;
  466. record.dwMarket = CStock::marketUnknown;
  467. return Add( record );
  468. }
  469. // 操作记录数组,得到买入记录数
  470. int COpRecordContainer::GetBuyRecordCount()
  471. {
  472. int nCount = 0;
  473. for( int i=0; i<GetSize(); i++ )
  474. {
  475. OPRECORD & record = ElementAt(i);
  476. if( STRATEGY_OPTYPE_BUY == record.lOpType )
  477. nCount ++;
  478. }
  479. return nCount;
  480. }
  481. // 操作记录数组,是否有szCode股票的买入记录
  482. BOOL COpRecordContainer::HasBuyStock( const char * szCode )
  483. {
  484. if( NULL == szCode || strlen(szCode) < 0 )
  485. return FALSE;
  486. for( int i=0; i<GetSize(); i++ )
  487. {
  488. OPRECORD & record = ElementAt(i);
  489. if( STRATEGY_OPTYPE_BUY == record.lOpType )
  490. {
  491. if( 0 == strncmp( record.szCode, szCode, min(sizeof(record.szCode),strlen(szCode)) ) )
  492. return TRUE;
  493. }
  494. }
  495. return FALSE;
  496. }
  497. // 操作记录数组,统计结果:操作次数,成功次数,最大收益,最低收益
  498. BOOL COpRecordContainer::StatResults( int *pnTimes, int *pnVictoryTimes, double *pdYieldMax, double *pdYieldMin )
  499. {
  500. int nTimes = 0, nVictoryTimes = 0;
  501. double dYieldMax = 0, dYieldMin = 0;
  502. for( int i=0; i<GetSize(); i++ )
  503. {
  504. OPRECORD & record = ElementAt(i);
  505. if( STRATEGY_OPTYPE_BUY != record.lOpType )
  506. continue;
  507. // 查找当前买入操作的对应卖出操作
  508. for( int j=i+1; j<GetSize(); j++ )
  509. {
  510. OPRECORD & record2 = ElementAt(j);
  511. if( STRATEGY_OPTYPE_SELL == record2.lOpType && 0 == strncmp(record.szCode,record2.szCode,sizeof(record.szCode)) )
  512. { // 如果是卖出操作,根据买入价格和卖出价格计算收益率
  513. if( record.dwShare > 0 && record2.dwShare > 0 )
  514. {
  515. double dBuy = record.dSharePrice + record.dRateCost/record.dwShare;
  516. double dSell = record2.dSharePrice - record2.dRateCost/record2.dwShare;
  517. if( dBuy > 1e-4 )
  518. {
  519. double dYield = (dSell - dBuy)/dBuy;
  520. nTimes ++;
  521. if( dYield > 0 ) nVictoryTimes ++;
  522. if( 1 == nTimes ) dYieldMax = dYieldMin = dYield;
  523. if( dYieldMax < dYield ) dYieldMax = dYield;
  524. if( dYieldMin > dYield ) dYieldMin = dYield;
  525. }
  526. }
  527. break;
  528. }
  529. }
  530. }
  531. if( pnTimes ) *pnTimes = nTimes;
  532. if( pnVictoryTimes ) *pnVictoryTimes = nVictoryTimes;
  533. if( pdYieldMax ) *pdYieldMax = dYieldMax;
  534. if( pdYieldMin ) *pdYieldMin = dYieldMin;
  535. return TRUE;
  536. }
  537. //////////////////////////////////////////////////////////////////////
  538. // CAssetSerialContainer 
  539. // 资产序列数组,按时间排序插入
  540. BOOL CAssetSerialContainer::SortInsert( ASSETSERIAL serial )
  541. {
  542. BOOL bAdded = FALSE;
  543. for( int i=GetSize()-1; i>=0; i-- )
  544. {
  545. ASSETSERIAL & se = ElementAt(i);
  546. if( se.time == serial.time )
  547. {
  548. se.dAsset = serial.dAsset;
  549. se.dCash = serial.dCash;
  550. bAdded = TRUE;
  551. break;
  552. }
  553. else if( se.time < serial.time )
  554. {
  555. InsertAt( i+1, serial );
  556. bAdded = TRUE;
  557. break;
  558. }
  559. }
  560. if( !bAdded )
  561. InsertAt( 0, serial );
  562. return TRUE;
  563. }
  564. // 资产序列数组,获得资产序列标准差
  565. BOOL CAssetSerialContainer::GetStdDev( double *pdStdDev, double *pdXiapu )
  566. {
  567. if( GetSize() <= 0 )
  568. return FALSE;
  569. double dInit = ElementAt(0).dAsset;
  570. if( dInit < 1e-4 )
  571. return FALSE;
  572. double dSum = 0., dSquareSum = 0.;
  573. for( int k = 0; k<GetSize(); k++ )
  574. {
  575. double dNow = (ElementAt(k).dAsset - dInit) / dInit;
  576. dSum += dNow;
  577. dSquareSum += dNow*dNow;
  578. }
  579. double dAverage = dSum / GetSize();
  580. if( dAverage < 1e-4 )
  581. return FALSE;
  582. double dStdDev = dSquareSum / GetSize() - ( dAverage*dAverage );
  583. if( dStdDev > 0 )
  584. dStdDev = sqrt( dStdDev );
  585. if( pdStdDev ) *pdStdDev = dStdDev;
  586. if( pdXiapu ) *pdXiapu = (dStdDev / dAverage);
  587. return TRUE;
  588. }
  589. //////////////////////////////////////////////////////////////////////
  590. // CTechStock
  591. CTechStock::CTechStock( )
  592. {
  593. m_bAutoDelete = TRUE;
  594. m_kdata.SetKType(CKData::ktypeDay);
  595. m_kdataLong.SetKType(CKData::ktypeDay);
  596. }
  597. CTechStock::CTechStock( const CTechStock & src )
  598. {
  599. *this = src;
  600. }
  601. CTechStock & CTechStock::operator = ( const CTechStock &src )
  602. {
  603. m_bAutoDelete = FALSE;
  604. m_info = src.m_info;
  605. m_kdata = src.m_kdata;
  606. m_kdataLong = src.m_kdataLong;
  607. m_techs.Copy( src.m_techs );
  608. m_techsLong.Copy( src.m_techsLong );
  609. return *this;
  610. }
  611. void CTechStock::SetAutoDelete( BOOL bAutoDelete )
  612. {
  613. m_bAutoDelete = bAutoDelete;
  614. }
  615. CTechStock::~CTechStock( )
  616. {
  617. Clear( );
  618. }
  619. // 清除内存
  620. void CTechStock::Clear( )
  621. {
  622. if( m_bAutoDelete )
  623. {
  624. for( int i=0; i<m_techs.GetSize(); i++ )
  625. {
  626. CTechnique * pTech = (CTechnique *)m_techs.ElementAt(i);
  627. if( pTech )
  628. delete pTech;
  629. }
  630. for( i=0; i<m_techsLong.GetSize(); i++ )
  631. {
  632. CTechnique * pTech = (CTechnique *)m_techsLong.ElementAt(i);
  633. if( pTech )
  634. delete pTech;
  635. }
  636. }
  637. m_techs.RemoveAll();
  638. m_techsLong.RemoveAll();
  639. }
  640. // 指定日期,指定操作,指定委托价格,得到股票的成交价格
  641. BOOL CTechStock::GetPriceOK( long lOpType, CSPTime tmCur, DWORD dwShare, double dSharePrice, double *pdPriceOK )
  642. {
  643. double dPriceOK = dSharePrice;
  644. CSPTime sptimeCur(tmCur.GetTime());
  645. DWORD dwDate = sptimeCur.ToStockTimeDay();
  646. int nIndex = m_kdata.GetIndexByDate( dwDate );
  647. if( -1 == nIndex )
  648. return FALSE;
  649. KDATA & kd = m_kdata.ElementAt(nIndex);
  650. if( STRATEGY_OPTYPE_BUY == lOpType )
  651. {
  652. if( dSharePrice < kd.m_fLow )
  653. return FALSE;
  654. if( dSharePrice > kd.m_fOpen )
  655. dPriceOK = kd.m_fOpen;
  656. else
  657. dPriceOK = dSharePrice;
  658. }
  659. else if( STRATEGY_OPTYPE_SELL == lOpType )
  660. {
  661. if( dSharePrice > kd.m_fHigh )
  662. return FALSE;
  663. if( dSharePrice < kd.m_fOpen )
  664. dPriceOK = kd.m_fOpen;
  665. else
  666. dPriceOK = dSharePrice;
  667. }
  668. else
  669. return FALSE;
  670. if( pdPriceOK ) *pdPriceOK = dPriceOK;
  671. return TRUE;
  672. }
  673. // 指定日期是否停牌
  674. BOOL CTechStock::IsStopTrading( CSPTime tmCur )
  675. {
  676. CSPTime sptimeCur(tmCur.GetTime());
  677. DWORD dwDate = sptimeCur.ToStockTimeDay();
  678. int nIndex = m_kdata.GetIndexByDate( dwDate );
  679. if( -1 == nIndex )
  680. {
  681. if( -1 != m_kdata.GetAboutIndexByDate( dwDate ) )
  682. return TRUE;
  683. return FALSE;
  684. }
  685. KDATA & kd = m_kdata.ElementAt(nIndex);
  686. float fLastClose = kd.m_fOpen;
  687. if( nIndex > 0 )
  688. fLastClose = m_kdata.ElementAt(nIndex-1).m_fClose;
  689. if( fabs(kd.m_fOpen-kd.m_fClose) < 1e-4 && fabs(kd.m_fOpen-kd.m_fHigh) < 1e-4
  690. && fabs(kd.m_fOpen-kd.m_fLow) < 1e-4 && fabs(kd.m_fOpen-fLastClose) < 1e-4 )
  691. return TRUE;
  692. return FALSE;
  693. }
  694. // 得到股票的收盘价
  695. BOOL CTechStock::GetClosePrice( CSPTime tmCur, double *pdPrice )
  696. {
  697. CSPTime sptimeCur(tmCur.GetTime());
  698. DWORD dwDate = sptimeCur.ToStockTimeDay();
  699. int nIndex = m_kdata.GetAboutIndexByDate( dwDate );
  700. if( -1 == nIndex )
  701. {
  702. SP_ASSERT( FALSE );
  703. return FALSE;
  704. }
  705. KDATA & kd = m_kdata.ElementAt(nIndex);
  706. if( pdPrice ) *pdPrice = kd.m_fClose;
  707. return TRUE;
  708. }
  709. // 得到股票的收盘价涨幅%
  710. BOOL CTechStock::GetCloseDiffPercent( CSPTime tmCur, double *pdDiffPercent )
  711. {
  712. if( pdDiffPercent ) *pdDiffPercent = 0;
  713. CSPTime sptimeCur(tmCur.GetTime());
  714. DWORD dwDate = sptimeCur.ToStockTimeDay();
  715. int nIndex = m_kdata.GetIndexByDate( dwDate );
  716. if( -1 == nIndex || nIndex <= 0 )
  717. {
  718. return FALSE;
  719. }
  720. KDATA & kd = m_kdata.ElementAt(nIndex);
  721. KDATA & kdLast = m_kdata.ElementAt(nIndex-1);
  722. if( pdDiffPercent && kdLast.m_fClose > 1e-4 )
  723. {
  724. *pdDiffPercent = 100. * (kd.m_fClose-kdLast.m_fClose)/kdLast.m_fClose;
  725. }
  726. return TRUE;
  727. }
  728. /////////////////////////////////////////////////////////////////////////////
  729. // CTechStockContainer
  730. CTechStockContainer::~CTechStockContainer( )
  731. {
  732. Clear( );
  733. }
  734. void CTechStockContainer::Clear( )
  735. {
  736. m_infoIndex.Clear();
  737. m_kdataIndex.Clear();
  738. m_kdataIndex.SetKType(CKData::ktypeDay);
  739. for( int i=0; i<m_techsIndex.GetSize(); i++ )
  740. {
  741. CTechnique * pTech = (CTechnique *)m_techsIndex.ElementAt(i);
  742. if( pTech )
  743. delete pTech;
  744. }
  745. m_techsIndex.RemoveAll();
  746. for( i=0; i<GetSize(); i++ )
  747. {
  748. CTechStock & stock = ElementAt(i);
  749. stock.Clear( );
  750. }
  751. RemoveAll();
  752. }
  753. // 给定CTechStock,日期tmCur,资金dCash,交易费率rate,操作条件opparam,
  754. // 现在拥有股票数量nOwnedStockCount,计算需要买入的股票数量和委托价格及委托时间,
  755. // 如果不需要买入,返回FALSE
  756. BOOL CTechStockContainer::GetShouldBuyShare( CTechStock & techstock, CSPTime tmCur, double dCash, CRateParam &rate, COpParam &opparam, int nOwnedStockCount,
  757. CSPTime *ptmOp, DWORD *pdwShare, double *pdSharePrice )
  758. {
  759. CSPTime tmOp = tmCur;
  760. DWORD dwShare = 0;
  761. double dSharePrice = 0;
  762. CSPTime sptimeCur(tmCur.GetTime());
  763. DWORD dwDate = sptimeCur.ToStockTimeDay();
  764. int nIndex = techstock.m_kdata.GetIndexByDate( dwDate ); // 得到nIndex,指向techstock.m_kdata数组的当前日期位置
  765. if( -1 == nIndex )
  766. return FALSE;
  767. double dPriceNow = techstock.m_kdata.ElementAt(nIndex).m_fClose; // 当前价
  768. // 买入判断
  769. BOOL bBuy = TRUE;
  770. if( COpParam::logicOr == opparam.m_nBuyLogic ) // 全部条件还是任一条件
  771. bBuy = FALSE;
  772. for( int i=0; i<techstock.m_techs.GetSize(); i++ ) // 每一个设定指标,分别判断
  773. {
  774. CTechnique * pTech = (CTechnique *)techstock.m_techs.ElementAt(i); // 技术指标
  775. SP_ASSERT( NULL != pTech );
  776. if( NULL == pTech )
  777. continue;
  778. int nIntensity = pTech->GetSignal( nIndex ); // 当前买卖信号
  779. if( COpParam::logicOr == opparam.m_nBuyLogic )
  780. {
  781. if( nIntensity >= opparam.m_nBuyLimit ) // 买卖信号是否达到所需条件
  782. bBuy = TRUE;
  783. }
  784. else
  785. {
  786. if( nIntensity < opparam.m_nBuyLimit )
  787. bBuy = FALSE;
  788. }
  789. }
  790. // Long and Index Trend
  791. if( bBuy )
  792. {
  793. // 如果技术指标判断为买入,判断是否满足长周期趋势和指数趋势
  794. if( opparam.m_bLongTrend ) // 长周期趋势
  795. {
  796. int nIndexLong = techstock.m_kdataLong.GetAboutIndexByDate( dwDate );
  797. if( opparam.m_nKTypeLong > opparam.m_nKType )
  798. nIndexLong --;
  799. if( nIndexLong >= 0 )
  800. {
  801. for( i=0; i<techstock.m_techsLong.GetSize(); i++ )
  802. {
  803. CTechnique * pTech = (CTechnique *)techstock.m_techsLong.ElementAt(i);
  804. SP_ASSERT( NULL != pTech );
  805. if( NULL == pTech )
  806. continue;
  807. pTech->ClearLastIntensity();
  808. int nIntensity = pTech->GetIntensity( nIndexLong ); // 得到当前趋势
  809. if( !ITS_ISBUY(nIntensity) )
  810. bBuy = FALSE;
  811. }
  812. }
  813. }
  814. if( opparam.m_bIndexTrend ) // 指数趋势
  815. {
  816. int nIndexIndex = m_kdataIndex.GetAboutIndexByDate( dwDate );
  817. if( opparam.m_nKTypeIndex > opparam.m_nKType )
  818. nIndexIndex --;
  819. if( nIndexIndex >= 0 )
  820. {
  821. for( i=0; i<m_techsIndex.GetSize(); i++ )
  822. {
  823. CTechnique * pTech = (CTechnique *)m_techsIndex.ElementAt(i);
  824. SP_ASSERT( NULL != pTech );
  825. if( NULL == pTech )
  826. continue;
  827. pTech->ClearLastIntensity();
  828. int nIntensity = pTech->GetIntensity( nIndexIndex );
  829. if( !ITS_ISBUY(nIntensity) )
  830. bBuy = FALSE;
  831. }
  832. }
  833. }
  834. }
  835. if( bBuy ) // 确定买入了
  836. {
  837. if( !opparam.GetNextTradeTime(tmCur, tmOp) ) // 操作日期,下一个交易日
  838. return FALSE;
  839. if( opparam.m_nStoreDiv-nOwnedStockCount <= 0 ) // 股票已经够多了,不能再买入新的了
  840. return FALSE;
  841. double dUseCash = dCash / (opparam.m_nStoreDiv-nOwnedStockCount); // 需使用资金
  842. if( dCash < dUseCash )
  843. dUseCash = dCash; // 资金不够,则有多少用多少
  844. dSharePrice = opparam.m_dBuyMulti * dPriceNow;
  845. double dTemp = dSharePrice * ( 1 + rate.GetRate( techstock.m_info ) );
  846. if( fabs(dTemp) < 1e-4 || dUseCash < 1e-4 )
  847. return FALSE;
  848. dwShare = (DWORD)( dUseCash / dTemp ); // 买入股数
  849. dwShare = ( dwShare / 100 ) * 100; // 取整
  850. if( 0 == dwShare )
  851. return FALSE;
  852. if( ptmOp ) *ptmOp = tmOp;
  853. if( pdwShare ) *pdwShare = dwShare;
  854. if( pdSharePrice ) *pdSharePrice = dSharePrice;
  855. return TRUE;
  856. }
  857. return FALSE;
  858. }
  859. // 给定CTechStock,日期tmCur,资金dCash,拥有股票own(含有买入时价格),操作条件opparam,
  860. // 现在拥有股票数量nOwnedStockCount,计算需要卖出的股票数量和委托价格及委托时间,
  861. // 如果不需要卖出,返回FALSE
  862. BOOL CTechStockContainer::GetShouldSellShare( CTechStock & techstock, CSPTime tmCur, STOCKOWN & own, COpParam &opparam,
  863. CSPTime *ptmOp, DWORD *pdwShare, double *pdSharePrice )
  864. {
  865. CSPTime tmOp = tmCur;
  866. DWORD dwShare = 0;
  867. double dSharePrice = 0;
  868. CSPTime sptimeCur(tmCur.GetTime());
  869. DWORD dwDate = sptimeCur.ToStockTimeDay();
  870. int nIndex = techstock.m_kdata.GetIndexByDate( dwDate ); // 得到nIndex,指向techstock.m_kdata数组的当前日期位置
  871. if( -1 == nIndex )
  872. return FALSE;
  873. double dPriceNow = techstock.m_kdata.ElementAt(nIndex).m_fClose; // 当前价
  874. // 卖出判断
  875. BOOL bSell = FALSE;
  876. if( COpParam::logicAnd == opparam.m_nSellLogic ) // 全部条件还是任一条件
  877. bSell = TRUE;
  878. for( int i=0; i<techstock.m_techs.GetSize(); i++ ) // 每一个技术指标,分别判断
  879. {
  880. CTechnique * pTech = (CTechnique *)techstock.m_techs.ElementAt(i);
  881. SP_ASSERT( NULL != pTech );
  882. if( NULL == pTech )
  883. continue;
  884. int nIntensity = pTech->GetSignal( nIndex ); // 当前买卖信号
  885. if( COpParam::logicAnd == opparam.m_nSellLogic )
  886. {
  887. if( nIntensity > opparam.m_nSellLimit ) // 买卖信号是否达到所需条件
  888. bSell = FALSE;
  889. }
  890. else
  891. {
  892. if( nIntensity <= opparam.m_nSellLimit )
  893. bSell = TRUE;
  894. }
  895. }
  896. // StopLosing and StopProfit 止损和止赢
  897. if( opparam.m_bStopLosing && dPriceNow < own.dBuyPrice * (1-opparam.m_dStopLosing) ) // 止损
  898. bSell = TRUE;
  899. if( opparam.m_bStopProfit && dPriceNow > own.dBuyPrice * (1+opparam.m_dStopProfit) ) // 止赢
  900. bSell = TRUE;
  901. if( bSell ) // 确定卖出了
  902. {
  903. if( !opparam.GetNextTradeTime(tmCur, tmOp) ) // 操作日期,下一个交易日
  904. return FALSE;
  905. dwShare = own.dwShare;
  906. dSharePrice = opparam.m_dSellMulti * dPriceNow;
  907. if( ptmOp ) *ptmOp = tmOp;
  908. if( pdwShare ) *pdwShare = dwShare;
  909. if( pdSharePrice ) *pdSharePrice = dSharePrice;
  910. return TRUE;
  911. }
  912. return FALSE;
  913. }
  914. // 得到某只股票szCode在日期tmCur的收盘价
  915. BOOL CTechStockContainer::GetClosePrice( const char * szCode, CSPTime tmCur, double * pdPrice )
  916. {
  917. if( NULL == szCode || strlen(szCode) <= 0 || GetSize() <= 0 )
  918. return FALSE;
  919. for( int j=0; j<GetSize(); j++ )
  920. {
  921. CTechStock & techstock = ElementAt(j);
  922. if( techstock.m_info.IsEqualTo( CStock::marketUnknown, szCode ) )
  923. {
  924. return techstock.GetClosePrice( tmCur, pdPrice );
  925. }
  926. }
  927. return FALSE;
  928. }
  929. // 得到某日的总资产
  930. BOOL CTechStockContainer::GetSumAsset( CSPTime tmCur, CStockOwnContainer &container, double * pdAsset )
  931. {
  932. if( GetSize() <= 0 )
  933. return FALSE;
  934. double dAsset = 0;
  935. for( int i=0; i<container.GetSize(); i++ )
  936. {
  937. STOCKOWN & own = container.ElementAt(i);
  938. double dPrice = 0;
  939. if( !GetClosePrice( own.szCode, tmCur, &dPrice ) )
  940. return FALSE;
  941. dAsset += dPrice * own.dwShare;
  942. }
  943. if( pdAsset ) *pdAsset = dAsset;
  944. return TRUE;
  945. }
  946. // 得到下一个有成交量的交易日
  947. BOOL CTechStockContainer::GetNextExistTradeTime( CSPTime tmCur, CSPTime & tmNext )
  948. {
  949. CSPTime sptime(tmCur.GetTime());
  950. DWORD dateCur = sptime.ToStockTimeDay( );
  951. DWORD dateNext = -1;
  952. for( int i=0; i<GetSize(); i++ )
  953. {
  954. CTechStock & techstock = ElementAt(i);
  955. int nIndex = techstock.m_kdata.GetAboutIndexByDate( dateCur );
  956. if( -1 != nIndex && nIndex+1 < techstock.m_kdata.GetSize() )
  957. {
  958. if( -1 == dateNext )
  959. dateNext = techstock.m_kdata.ElementAt(nIndex+1).m_date;
  960. else if( dateNext > techstock.m_kdata.ElementAt(nIndex+1).m_date )
  961. dateNext = techstock.m_kdata.ElementAt(nIndex+1).m_date;
  962. }
  963. }
  964. if( -1 != dateNext && sptime.FromStockTimeDay( dateNext ) )
  965. {
  966. tmNext = sptime.GetTime();
  967. return TRUE;
  968. }
  969. return FALSE;
  970. }
  971. /////////////////////////////////////////////////////////////////////////////
  972. // CStrategy
  973. // 给定策略文件,得到策略名称
  974. CSPString CStrategy::GetName( LPCTSTR lpszPath )
  975. {
  976. if( NULL == lpszPath || strlen(lpszPath) <= 0 )
  977. return "";
  978. CSPString strName;
  979. CStrategy doc;
  980. CSPFile file;
  981. if( file.Open( lpszPath, CSPFile::modeRead) )
  982. {
  983. CSPArchive ar(&file, CSPArchive::load | CSPArchive::bNoFlushOnDelete);
  984. if( file.GetLength() > 0 )
  985. doc.Serialize( ar, NULL, 0 );
  986. ar.Close();
  987. file.Close();
  988. strName = doc.m_strName;
  989. }
  990. if( strName.IsEmpty() )
  991. strName = lpszPath;
  992. return strName;
  993. }
  994. /////////////////////////////////////////////////////////////////////////////
  995. // CStrategy construction/destruction
  996. char szCELFileMagic[] = "BALANG CEL FILE.";
  997. DWORD dwCELFileVersion = 0x20000000;
  998. CStrategy::CStrategy()
  999. {
  1000. SimuReset( );
  1001. RealReset( );
  1002. }
  1003. CStrategy::~CStrategy()
  1004. {
  1005. ClearCache( );
  1006. }
  1007. // 打开策略文件
  1008. BOOL CStrategy::OpenStrategyFile( LPCTSTR lpszPathName, LPSTR lpErr, UINT nMaxSize )
  1009. {
  1010. CSPFile file;
  1011. if( NULL != lpszPathName && file.Open( lpszPathName, CSPFile::modeRead) )
  1012. {
  1013. if( 0 == file.GetLength() )
  1014. {
  1015. SetPathName(lpszPathName);
  1016. return TRUE;
  1017. }
  1018. CSPArchive ar(&file, CSPArchive::load | CSPArchive::bNoFlushOnDelete);
  1019. BOOL bSuccess = Serialize( ar, lpErr, nMaxSize );
  1020. ar.Close();
  1021. file.Close();
  1022. if( bSuccess )
  1023. SetPathName(lpszPathName);
  1024. return bSuccess;
  1025. }
  1026. SetPathName( NULL );
  1027. return FALSE;
  1028. }
  1029. BOOL CStrategy::SaveStrategyFile( LPCTSTR lpszPathName )
  1030. {
  1031. CSPString newName;
  1032. if( lpszPathName )
  1033. newName = lpszPathName;
  1034. if (newName.IsEmpty())
  1035. newName = m_strPathName;
  1036. CSPFile file;
  1037. if( file.Open( newName, CSPFile::modeCreate | CSPFile::modeWrite) )
  1038. {
  1039. CSPArchive ar(&file, CSPArchive::store);
  1040. Serialize( ar, NULL, 0 );
  1041. ar.Close();
  1042. file.Close();
  1043. SetPathName(newName);
  1044. return TRUE;
  1045. }
  1046. return FALSE;
  1047. }
  1048. /////////////////////////////////////////////////////////////////////////////
  1049. // CStrategy serialization
  1050. // 文件保存和读取
  1051. BOOL CStrategy::Serialize(CSPArchive& ar, LPSTR lpErr, UINT nMaxSize )
  1052. {
  1053. if( lpErr && nMaxSize>0 )
  1054. memset(lpErr,0,nMaxSize);
  1055. if (ar.IsStoring())
  1056. {
  1057. ar.Write( szCELFileMagic, sizeof(szCELFileMagic) );
  1058. ar << dwCELFileVersion;
  1059. ar << m_strName;
  1060. ar << m_strDescript;
  1061. m_stocks.Serialize( ar );
  1062. m_rate.Serialize( ar );
  1063. m_paramBuy.Serialize( ar );
  1064. m_paramSell.Serialize( ar );
  1065. m_paramLongTrend.Serialize( ar );
  1066. m_paramIndexTrend.Serialize( ar );
  1067. m_anTechsBuy.Serialize( ar );
  1068. m_anTechsSell.Serialize( ar );
  1069. m_anTechsLongTrend.Serialize( ar );
  1070. m_anTechsIndexTrend.Serialize( ar );
  1071. m_opparam.Serialize( ar );
  1072. // Simulation
  1073. ar << m_SimuCurrentStatus;
  1074. ar << m_SimuCurrentTime;
  1075. ar << m_SimuCurrentCash;
  1076. m_SimuStockOwn.Serialize( ar );
  1077. m_SimuOpRecord.Serialize( ar );
  1078. m_SimuNextOp.Serialize( ar );
  1079. m_SimuAssetSerial.Serialize( ar );
  1080. // Real Operation
  1081. ar << m_RealBeginTime;
  1082. ar << m_RealCurrentTime;
  1083. ar << m_RealCurrentCash;
  1084. m_RealStockOwn.Serialize( ar );
  1085. m_RealOpRecord.Serialize( ar );
  1086. m_RealNextOp.Serialize( ar );
  1087. m_RealAssetSerial.Serialize( ar );
  1088. }
  1089. else
  1090. {
  1091. char buffer[sizeof(szCELFileMagic)+1];
  1092. if( sizeof(szCELFileMagic) != ar.Read( buffer, sizeof(szCELFileMagic) )
  1093. || 0 != strncmp( buffer, szCELFileMagic, sizeof(szCELFileMagic) ) )
  1094. {
  1095. if( lpErr )
  1096. strncpy(lpErr,strategy_errfile,min(nMaxSize-1,strlen(strategy_errfile)) );
  1097. return FALSE;
  1098. }
  1099. ar >> m_dwFileVersion;
  1100. if( m_dwFileVersion > dwCELFileVersion )
  1101. {
  1102. if( lpErr )
  1103. strncpy(lpErr,strategy_errfilever,min(nMaxSize-1,strlen(strategy_errfilever)) );
  1104. return FALSE;
  1105. }
  1106. ar >> m_strName;
  1107. ar >> m_strDescript;
  1108. m_stocks.Serialize( ar );
  1109. m_rate.Serialize( ar );
  1110. m_paramBuy.Serialize( ar );
  1111. m_paramSell.Serialize( ar );
  1112. m_paramLongTrend.Serialize( ar );
  1113. m_paramIndexTrend.Serialize( ar );
  1114. m_anTechsBuy.Serialize( ar );
  1115. m_anTechsSell.Serialize( ar );
  1116. m_anTechsLongTrend.Serialize( ar );
  1117. m_anTechsIndexTrend.Serialize( ar );
  1118. m_opparam.Serialize( ar );
  1119. // Simulation
  1120. ar >> m_SimuCurrentStatus;
  1121. ar >> m_SimuCurrentTime;
  1122. ar >> m_SimuCurrentCash;
  1123. m_SimuStockOwn.Serialize( ar );
  1124. m_SimuOpRecord.Serialize( ar );
  1125. m_SimuNextOp.Serialize( ar );
  1126. m_SimuAssetSerial.Serialize( ar );
  1127. // Real Operation
  1128. ar >> m_RealBeginTime;
  1129. ar >> m_RealCurrentTime;
  1130. ar >> m_RealCurrentCash;
  1131. m_RealStockOwn.Serialize( ar );
  1132. m_RealOpRecord.Serialize( ar );
  1133. m_RealNextOp.Serialize( ar );
  1134. m_RealAssetSerial.Serialize( ar );
  1135. }
  1136. return TRUE;
  1137. }
  1138. BOOL CStrategy::DoFileSave( )
  1139. {
  1140. return SaveStrategyFile( GetPathName() );
  1141. }
  1142. BOOL CStrategy::OnClose( )
  1143. {
  1144. ClearCache( );
  1145. return TRUE;
  1146. }
  1147. void CStrategy::OnRealOpViewed( )
  1148. {
  1149. for( int i=0; i<m_RealNextOp.GetSize(); i++ )
  1150. m_RealNextOp.ElementAt(i).bViewed = TRUE;
  1151. }
  1152. /////////////////////////////////////////////////////////////////////////////
  1153. // CStrategy commands
  1154. void CStrategy::SetPathName( LPCTSTR lpszPathName )
  1155. {
  1156. m_strPathName = lpszPathName;
  1157. }
  1158. CSPString CStrategy::GetPathName( )
  1159. {
  1160. return m_strPathName;
  1161. }
  1162. // 设定策略名称
  1163. void CStrategy::SetName( LPCTSTR lpszName )
  1164. {
  1165. m_strName = lpszName;
  1166. }
  1167. // 得到策略名称
  1168. CSPString CStrategy::GetName( )
  1169. {
  1170. if( m_strName.IsEmpty() )
  1171. return GetPathName();
  1172. return m_strName;
  1173. }
  1174. // 设定策略描述
  1175. void CStrategy::SetDescript( LPCTSTR lpszDescript )
  1176. {
  1177. m_strDescript = lpszDescript;
  1178. }
  1179. // 得到策略描述
  1180. CSPString CStrategy::GetDescript( )
  1181. {
  1182. return m_strDescript;
  1183. }
  1184. // 得到策略被选股票
  1185. CSPStringArray & CStrategy::GetStocks( )
  1186. {
  1187. return m_stocks;
  1188. }
  1189. // 设定策略备选股票
  1190. void CStrategy::SetStocks( CSPStringArray & astr )
  1191. {
  1192. m_stocks.Copy( astr );
  1193. }
  1194. // 加入策略备选股票
  1195. void CStrategy::AddStock( LPCTSTR lpszCode )
  1196. {
  1197. m_stocks.AddStock( lpszCode );
  1198. }
  1199. // 移除策略备选股票
  1200. void CStrategy::RemoveStock( LPCTSTR lpszCode )
  1201. {
  1202. m_stocks.RemoveStock( lpszCode );
  1203. }
  1204. // 得到策略的一般性描述文字
  1205. CSPString CStrategy::GetStockTechString( )
  1206. {
  1207. int nStockShowCount = 3, nTechShowCount = 10;
  1208. CSPString strStock;
  1209. for( int i=0; i<m_stocks.GetSize() && i<nStockShowCount; i++ )
  1210. {
  1211. if( strStock.GetLength() > 0 )
  1212. strStock += ",";
  1213. CStockInfo info;
  1214. if( AfxGetStockContainer().GetStockInfo( m_stocks.ElementAt(i), &info ) )
  1215. //#ifdef CLKLAN_ENGLISH_US
  1216. // strStock += info.GetStockCode();
  1217. //#else
  1218. strStock += info.GetStockName();
  1219. //#endif
  1220. else
  1221. strStock += m_stocks.ElementAt(i);
  1222. }
  1223. if( strStock.GetLength() == 0 )
  1224. strStock = strategy_noselectedstock;
  1225. else if( m_stocks.GetSize() > nStockShowCount )
  1226. strStock += "...";
  1227. strStock += ";    ";
  1228. CSPString strTech;
  1229. for( i=0; i<m_anTechsBuy.GetSize() && i<nTechShowCount; i++ )
  1230. {
  1231. if( strTech.GetLength() > 0 )
  1232. strTech += ",";
  1233. strTech += AfxGetSTTShortName(m_anTechsBuy[i]);
  1234. }
  1235. if( strTech.GetLength() == 0 )
  1236. strTech = strategy_noselectedtech;
  1237. else if( m_anTechsBuy.GetSize() > nTechShowCount )
  1238. strTech += "...";
  1239. return strStock + strTech;
  1240. }
  1241. // 交易费率、操作条件等
  1242. CRateParam & CStrategy::GetRateParam( ) { return m_rate; }
  1243. COpParam & CStrategy::GetOpParam( ) { return m_opparam; }
  1244. CTechParameters & CStrategy::GetTechParametersBuy( ) { return m_paramBuy; }
  1245. CTechParameters & CStrategy::GetTechParametersSell( ) { return m_paramSell; }
  1246. CTechParameters & CStrategy::GetTechParametersLongTrend( ) { return m_paramLongTrend; }
  1247. CTechParameters & CStrategy::GetTechParametersIndexTrend( ) { return m_paramIndexTrend; }
  1248. CSPDWordArray & CStrategy::GetSelectedTechsBuy( ) { return m_anTechsBuy; }
  1249. CSPDWordArray & CStrategy::GetSelectedTechsSell( ) { return m_anTechsSell; }
  1250. CSPDWordArray & CStrategy::GetSelectedTechsLongTrend( ) { return m_anTechsLongTrend; }
  1251. CSPDWordArray & CStrategy::GetSelectedTechsIndexTrend( ) { return m_anTechsIndexTrend; }
  1252. /////////////////////////////////////////////////////////////////////////
  1253. // Cache
  1254. // 准备数据,读取K线数据,长周期K线数据,生成技术指标对象
  1255. BOOL CStrategy::PrepareData( SIMULATION_CALLBACK fnCallback, void * cookie )
  1256. {
  1257. if( m_techstocks.GetSize() == m_stocks.GetSize() )
  1258. return TRUE;
  1259. ClearCache( );
  1260. // m_techstocks.m_kdataIndex m_techstocks.m_infoIndex
  1261. if( m_opparam.m_bIndexTrend ) // 指数K线数据
  1262. {
  1263. CStockInfo infoIndex;
  1264. if( AfxGetStockContainer().GetStockInfo( STKLIB_CODE_MAIN, &infoIndex ) )
  1265. {
  1266. m_techstocks.m_infoIndex = infoIndex;
  1267. CStock stockIndex;
  1268. stockIndex.SetStockInfo( &infoIndex );
  1269. stockIndex.SetDatabase( &AfxGetDB() );
  1270. stockIndex.PrepareData( CStock::dataK, m_opparam.m_nKTypeIndex );
  1271. CKData & kdataIndex = stockIndex.GetKData(m_opparam.m_nKTypeIndex);
  1272. kdataIndex.SetMaindataType( m_opparam.m_nMaindataType );
  1273. m_techstocks.m_kdataIndex = kdataIndex;
  1274. // m_techstocks.m_techsIndex
  1275. for( int j=0; j<m_anTechsIndexTrend.GetSize(); j++ )
  1276. {
  1277. CTechnique * pTech = CTechnique::CreateTechnique( m_anTechsIndexTrend[j], &(m_techstocks.m_kdataIndex) );
  1278. m_paramIndexTrend.FindParameters( m_anTechsIndexTrend[j], pTech );
  1279. m_techstocks.m_techsIndex.Add( pTech );
  1280. }
  1281. }
  1282. }
  1283. m_techstocks.SetSize( m_stocks.GetSize() );
  1284. int nStockCount = 0;
  1285. for( int i=0; i<m_stocks.GetSize(); i++ ) // 读取每一只备选股票的数据
  1286. {
  1287. CStockInfo info;
  1288. if( AfxGetStockContainer().GetStockInfo( m_stocks.ElementAt(i), &info ) )
  1289. {
  1290. // CTechStock::m_info;
  1291. CTechStock temp;
  1292. temp.m_info = info;
  1293. m_techstocks.SetAt( nStockCount, temp );
  1294. CTechStock & techstock = m_techstocks.ElementAt(nStockCount);
  1295. nStockCount ++;
  1296. // CTechStock::m_kdata
  1297. CStock stock;
  1298. stock.SetStockInfo( &info );
  1299. AfxPrepareStockData( &AfxGetDB(), stock, m_opparam.m_nKType, CKData::formatXDRdown, m_opparam.m_nMaindataType, FALSE, FALSE );
  1300. techstock.m_kdata = stock.GetKData(m_opparam.m_nKType);
  1301. // CTechStock::m_techs
  1302. techstock.SetAutoDelete( TRUE );
  1303. for( int j=0; j<m_anTechsBuy.GetSize(); j++ )
  1304. {
  1305. CTechnique * pTech = CTechnique::CreateTechnique( m_anTechsBuy[j], &(techstock.m_kdata) );
  1306. m_paramBuy.FindParameters( m_anTechsBuy[j], pTech );
  1307. techstock.m_techs.Add( pTech );
  1308. }
  1309. // CTechStock::m_kdataLong
  1310. if( m_opparam.m_bLongTrend )
  1311. {
  1312. AfxPrepareStockData( &AfxGetDB(), stock, m_opparam.m_nKTypeLong, CKData::formatXDRdown, m_opparam.m_nMaindataType, FALSE, FALSE );
  1313. techstock.m_kdataLong = stock.GetKData( m_opparam.m_nKTypeLong );
  1314. // CTechStock::m_techsLong
  1315. for( j=0; j<m_anTechsLongTrend.GetSize(); j++ )
  1316. {
  1317. CTechnique * pTech = CTechnique::CreateTechnique( m_anTechsLongTrend[j], &(techstock.m_kdataLong) );
  1318. m_paramLongTrend.FindParameters( m_anTechsLongTrend[j], pTech );
  1319. techstock.m_techsLong.Add( pTech );
  1320. }
  1321. }
  1322. }
  1323. DWORD dwProgress = (DWORD)((i+1)*STRATEGY_MAXF_PROGRESS / m_stocks.GetSize());
  1324. if( fnCallback && !fnCallback( SIMULATION_PROGRESS, dwProgress, NULL, cookie ) )
  1325. {
  1326. ClearCache( );
  1327. nStockCount = 0;
  1328. break;
  1329. }
  1330. }
  1331. m_techstocks.SetSize( nStockCount );
  1332. if( fnCallback )
  1333. fnCallback( SIMULATION_PROGRESS, STRATEGY_MAX_PROGRESS, NULL, cookie );
  1334. return ( m_techstocks.GetSize() == m_stocks.GetSize() );
  1335. }
  1336. // 清除每个指标保存的上次趋势值
  1337. void CStrategy::ClearLastIntensity( )
  1338. {
  1339. for( int i=0; i<m_techstocks.GetSize(); i++ )
  1340. {
  1341. CTechStock & techstock = m_techstocks.ElementAt(i);
  1342. for( int nTech=0; nTech<techstock.m_techs.GetSize(); nTech++ )
  1343. {
  1344. CTechnique * pTech = (CTechnique *)techstock.m_techs.ElementAt(nTech);
  1345. if( pTech )
  1346. pTech->ClearLastIntensity();
  1347. }
  1348. }
  1349. }
  1350. void CStrategy::ClearCache( )
  1351. {
  1352. m_techstocks.Clear();
  1353. }
  1354. CTechStockContainer & CStrategy::GetTechStockContainer( )
  1355. {
  1356. return m_techstocks;
  1357. }
  1358. ////////////////////////////////////////////////////////////////////////
  1359. // Simulation
  1360. // 策略模拟:重新设定
  1361. void CStrategy::SimuReset( )
  1362. {
  1363. SimuSetStatusInit( );
  1364. m_SimuCurrentTime = m_opparam.GetBeginTime( );
  1365. m_SimuCurrentCash = m_opparam.m_nStartAmount;
  1366. m_SimuOpRecord.RemoveAll();
  1367. m_SimuNextOp.RemoveAll();
  1368. m_SimuStockOwn.RemoveAll();
  1369. m_SimuAssetSerial.RemoveAll();
  1370. SP_ASSERT( m_opparam.IsValid() );
  1371. }
  1372. // 策略模拟:进入下一个交易日
  1373. BOOL CStrategy::SimuGotoNextTime( )
  1374. {
  1375. CSPTime tmNext;
  1376. if( m_opparam.GetNextTradeTime( m_SimuCurrentTime, tmNext )
  1377. && m_opparam.IsInTimeZones( tmNext ) )
  1378. {
  1379. m_SimuCurrentTime = tmNext;
  1380. return TRUE;
  1381. }
  1382. return FALSE;
  1383. }
  1384. // 策略模拟:模拟的当前时间
  1385. CSPTime CStrategy::SimuGetCurrentTime( )
  1386. {
  1387. return m_SimuCurrentTime;
  1388. }
  1389. // 策略模拟:模拟的当前资金
  1390. double CStrategy::SimuGetCurrentCash( )
  1391. {
  1392. return m_SimuCurrentCash;
  1393. }
  1394. // 策略模拟:操作执行,bTimeStrict表示是否严格遵守计划时间
  1395. BOOL CStrategy::SimuOperate( OPRECORD record, BOOL bTimeStrict )
  1396. {
  1397. if( ! m_opparam.IsInTimeZones( record.time ) )
  1398. return FALSE;
  1399. if( bTimeStrict && m_SimuOpRecord.GetSize() > 0 && record.time < m_SimuOpRecord.ElementAt(m_SimuOpRecord.GetSize()-1).time )
  1400. return FALSE;
  1401. CStockInfo info;
  1402. if( strlen(record.szCode)>0
  1403. && ( !AfxGetStockContainer().GetStockInfo( record.szCode, &info )
  1404. || !info.IsValidStock() ) )
  1405. return FALSE;
  1406. double dAmount = record.dwShare * record.dSharePrice;
  1407. double dRateCost = record.dRateCost;
  1408. if( STRATEGY_OPTYPE_BUY == record.lOpType ) // 买入
  1409. {
  1410. if( m_SimuCurrentCash < dAmount+dRateCost )
  1411. return FALSE;
  1412. if( !m_SimuStockOwn.AddStock( info, record.dwShare, record.dSharePrice ) )
  1413. return FALSE;
  1414. m_SimuCurrentCash -= (dAmount+dRateCost);
  1415. }
  1416. else if( STRATEGY_OPTYPE_SELL == record.lOpType ) // 卖出
  1417. {
  1418. if( !m_SimuStockOwn.RemoveStock( info, record.dwShare ) )
  1419. return FALSE;
  1420. m_SimuCurrentCash += (dAmount-dRateCost);
  1421. }
  1422. else if( STRATEGY_OPTYPE_ADDSTOCK == record.lOpType )// 添加股票
  1423. {
  1424. if( !m_SimuStockOwn.AddStock( info, record.dwShare, record.dSharePrice ) )
  1425. return FALSE;
  1426. }
  1427. else if( STRATEGY_OPTYPE_REMOVESTOCK == record.lOpType )// 移除股票
  1428. {
  1429. if( !m_SimuStockOwn.RemoveStock( info, record.dwShare ) )
  1430. return FALSE;
  1431. }
  1432. else if( STRATEGY_OPTYPE_ADDCASH == record.lOpType ) // 添加资金
  1433. {
  1434. m_SimuCurrentCash += record.dSharePrice;
  1435. }
  1436. else if( STRATEGY_OPTYPE_REMOVECASH == record.lOpType ) // 移除资金
  1437. {
  1438. if( m_SimuCurrentCash < record.dSharePrice )
  1439. return FALSE;
  1440. m_SimuCurrentCash -= record.dSharePrice;
  1441. }
  1442. else
  1443. return FALSE;
  1444. // Record
  1445. m_SimuOpRecord.Add( record );
  1446. return TRUE;
  1447. }
  1448. // 策略模拟:操作记录
  1449. COpRecordContainer & CStrategy::SimuGetOpRecord( )
  1450. {
  1451. return m_SimuOpRecord;
  1452. }
  1453. // 策略模拟:下一步操作
  1454. COpRecordContainer & CStrategy::SimuGetNextOp( )
  1455. {
  1456. return m_SimuNextOp;
  1457. }
  1458. // 策略模拟:当前拥有股票
  1459. CStockOwnContainer & CStrategy::SimuGetStockOwn( )
  1460. {
  1461. return m_SimuStockOwn;
  1462. }
  1463. // 策略模拟:总资产序列
  1464. CAssetSerialContainer & CStrategy::SimuGetAssetSerial( )
  1465. {
  1466. return m_SimuAssetSerial;
  1467. }
  1468. // 策略模拟:当前进度
  1469. DWORD CStrategy::SimuGetCurrentProgress( DWORD dwProgressMax )
  1470. {
  1471. return m_opparam.GetProgress( m_SimuCurrentTime, dwProgressMax );
  1472. }
  1473. // 策略模拟:给定时间的总资产
  1474. double CStrategy::SimuGetAsset( CSPTime tmCur )
  1475. {
  1476. double dAsset = 0;
  1477. if( m_techstocks.GetSumAsset( tmCur, m_SimuStockOwn, &dAsset ) ) // 计算总资产
  1478. {
  1479. dAsset += m_SimuCurrentCash;
  1480. ASSETSERIAL serial;
  1481. memset( &serial, 0, sizeof(serial) );
  1482. serial.time = tmCur.GetTime();
  1483. serial.dAsset = dAsset;
  1484. serial.dCash = m_SimuCurrentCash;
  1485. m_SimuAssetSerial.SortInsert( serial );
  1486. return dAsset;
  1487. }
  1488. else
  1489. {
  1490. for( int i=m_SimuAssetSerial.GetSize()-1; i>=0; i-- )
  1491. {
  1492. ASSETSERIAL & serial = m_SimuAssetSerial.ElementAt(i);
  1493. if( serial.time <= tmCur.GetTime() )
  1494. return serial.dAsset;
  1495. }
  1496. }
  1497. return m_opparam.m_nStartAmount; // 初始总资产
  1498. }
  1499. // 策略模拟:当前收益
  1500. double CStrategy::SimuGetCurrentYield( )
  1501. {
  1502. if( m_opparam.m_nStartAmount > 0 )
  1503. return STRATEGY_BASEF_YIELD * SimuGetAsset(m_SimuCurrentTime) / m_opparam.m_nStartAmount;
  1504. return STRATEGY_BASEF_YIELD;
  1505. }
  1506. // 策略模拟:当前指数上涨多少
  1507. double CStrategy::SimuGetCurrentYieldIndexPercent( )
  1508. {
  1509. CSPTime sptmBegin( m_opparam.GetBeginTime().GetTime() );
  1510. CSPTime sptmNow( m_SimuCurrentTime.GetTime() );
  1511. DWORD dateBegin = sptmBegin.ToStockTimeDay();
  1512. DWORD dateNow = sptmNow.ToStockTimeDay();
  1513. CKData & kdata = AfxGetStockMain().GetKData(m_opparam.m_nKType);
  1514. int nIndexBegin = kdata.GetAboutIndexByDate( dateBegin );
  1515. int nIndexNow = kdata.GetAboutIndexByDate( dateNow );
  1516. if( -1 == nIndexBegin || -1 == nIndexNow )
  1517. return 0;
  1518. if( kdata.ElementAt(nIndexBegin).m_fClose < 1e-4 )
  1519. return 0;
  1520. double dYield = ((double)kdata.ElementAt(nIndexNow).m_fClose) - kdata.ElementAt(nIndexBegin).m_fClose;
  1521. dYield = dYield / kdata.ElementAt(nIndexBegin).m_fClose;
  1522. return dYield;
  1523. }
  1524. // 策略模拟:当前收益百分数
  1525. double CStrategy::SimuGetCurrentYieldPercent( )
  1526. {
  1527. return ( SimuGetCurrentYield() - STRATEGY_BASEF_YIELD ) / STRATEGY_BASEF_YIELD;
  1528. }
  1529. // 策略模拟:执行下一步操作计划
  1530. BOOL CStrategy::SimuOperateNextop( CSPTime tmCur, COpRecordContainer & nextop, CTechStock & techstock )
  1531. {
  1532. for( int j=0; j<nextop.GetSize(); j++ ) // 每个计划依次执行
  1533. {
  1534. OPRECORD & record = nextop.ElementAt(j);
  1535. if( STRATEGY_OPTYPE_BUY != record.lOpType && STRATEGY_OPTYPE_SELL != record.lOpType )
  1536. continue;
  1537. if( tmCur.GetTime() >= record.time
  1538. && techstock.m_info.IsEqualTo( CStock::marketUnknown, record.szCode ) )
  1539. {
  1540. if( techstock.IsStopTrading(tmCur) ) // 停牌吗
  1541. {
  1542. CSPTime tmNext;
  1543. if( m_opparam.GetNextTradeTime(tmCur, tmNext) )
  1544. record.time = tmNext.GetTime(); // 下次再执行
  1545. continue;
  1546. }
  1547. double dPriceOK = record.dSharePrice;
  1548. if( techstock.GetPriceOK( record.lOpType, tmCur, record.dwShare, record.dSharePrice, &dPriceOK ) ) // 成交价
  1549. {
  1550. record.time = tmCur.GetTime();
  1551. record.dSharePrice = dPriceOK;
  1552. record.dRateCost = record.dwShare * record.dSharePrice * m_rate.GetRate(techstock.m_info);
  1553. SimuOperate( record );
  1554. }
  1555. else if( STRATEGY_OPTYPE_SELL == record.lOpType ) // 如果是卖出而没有成功,则顺延下一个交易日,直至卖出
  1556. {
  1557. CSPTime tmNext;
  1558. if( m_opparam.GetNextTradeTime(tmCur, tmNext) )
  1559. record.time = tmNext.GetTime();
  1560. if( techstock.GetClosePrice(tmCur,&dPriceOK) )
  1561. record.dSharePrice = dPriceOK * m_opparam.m_dSellMulti;
  1562. continue;
  1563. }
  1564. nextop.RemoveAt(j);
  1565. j --;
  1566. }
  1567. }
  1568. return TRUE;
  1569. }
  1570. // 策略模拟:模拟运行
  1571. BOOL CStrategy::SimuRun( SIMULATION_CALLBACK fnCallback, void * cookie )
  1572. {
  1573. // TIMEZONES
  1574. // 准备数据
  1575. if( !PrepareData( fnCallback, cookie ) )
  1576. return FALSE;
  1577. ClearLastIntensity( );
  1578. DWORD dwShare = 0; // Temp Data
  1579. double dSharePrice = 0; // Temp Data
  1580. CSPTime tmOp; // Temp Data
  1581. do {
  1582. CSPTime tmCur = SimuGetCurrentTime(); // 模拟当前时间
  1583. // Process
  1584. for( int i=0; i<m_techstocks.GetSize(); i++ ) // 每只股票依次判断
  1585. {
  1586. CTechStock & techstock = m_techstocks.ElementAt(i);
  1587. // Operate
  1588. SimuOperateNextop( tmCur, m_SimuNextOp, techstock ); // 执行今天的操作计划
  1589. // Judge Whether to operate, if yes, save to nextop
  1590. STOCKOWN own;
  1591. memset( &own, 0, sizeof(own) );
  1592. if( m_SimuStockOwn.HasThisStock( techstock.m_info, &own ) ) // 如果已经有这支股票,判断是否卖出
  1593. {
  1594. if( m_techstocks.GetShouldSellShare( techstock, tmCur, own, m_opparam, &tmOp, &dwShare, &dSharePrice ) )
  1595. { // 如果要卖出,加入下一步操作计划,下一个交易日执行
  1596. m_SimuNextOp.AddRecordUniqueStock( STRATEGY_OPTYPE_SELL, tmOp, techstock.m_info.GetStockCode(), dwShare, dSharePrice, dwShare*dSharePrice*m_rate.GetRate(techstock.m_info) );
  1597. }
  1598. }
  1599. else // 判断是否买入
  1600. {
  1601. if( m_techstocks.GetShouldBuyShare( techstock, tmCur, m_SimuCurrentCash, m_rate , m_opparam, m_SimuStockOwn.GetSize(), &tmOp, &dwShare, &dSharePrice )
  1602. && ( m_SimuStockOwn.GetSize() + m_SimuNextOp.GetBuyRecordCount() < m_opparam.m_nStoreDiv || m_SimuNextOp.HasBuyStock(techstock.m_info.GetStockCode()) ) )
  1603. { // 如果要买入,加入下一步操作计划,下一个交易日执行
  1604. m_SimuNextOp.AddRecordUniqueStock( STRATEGY_OPTYPE_BUY, tmOp, techstock.m_info.GetStockCode(), dwShare, dSharePrice, dwShare*dSharePrice*m_rate.GetRate(techstock.m_info) );
  1605. }
  1606. }
  1607. }
  1608. // 进度显示
  1609. DWORD dwProgress = SimuGetCurrentProgress( STRATEGY_MAX_PROGRESS );
  1610. double dYield = SimuGetCurrentYield( );
  1611. if( fnCallback && !fnCallback( SIMULATION_PROGRESS, dwProgress, NULL, cookie ) )
  1612. return FALSE;
  1613. if( fnCallback && !fnCallback( SIMULATION_YIELD, (DWORD)dYield, NULL, cookie ) )
  1614. return FALSE;
  1615. } while( SimuGotoNextTime() ); // 模拟的下一个交易日
  1616. if( fnCallback )
  1617. fnCallback( SIMULATION_PROGRESS, STRATEGY_MAX_PROGRESS, NULL, cookie );
  1618. return TRUE;
  1619. }
  1620. ////////////////////////////////////////////////////////////////////////
  1621. // Real
  1622. // 策略实战:重新设定
  1623. void CStrategy::RealReset( )
  1624. {
  1625. CSPTime tmLatest = CSPTime::GetCurrentTime();
  1626. AfxGetDB().GetTimeLocalRange( &tmLatest, NULL, NULL );
  1627. m_RealBeginTime = tmLatest;
  1628. m_RealCurrentTime = tmLatest;
  1629. m_RealCurrentCash = m_opparam.m_nStartAmount;
  1630. m_RealOpRecord.RemoveAll();
  1631. m_RealNextOp.RemoveAll();
  1632. m_RealStockOwn.RemoveAll();
  1633. m_RealAssetSerial.RemoveAll();
  1634. SP_ASSERT( m_opparam.IsValid() );
  1635. }
  1636. // 策略实战:下一个交易时间
  1637. BOOL CStrategy::RealGotoNextTime( )
  1638. {
  1639. CSPTime tmNext;
  1640. if( m_techstocks.GetNextExistTradeTime( RealGetCurrentTime(), tmNext ) )
  1641. {
  1642. m_RealCurrentTime = tmNext;
  1643. return TRUE;
  1644. }
  1645. return FALSE;
  1646. }
  1647. // 策略实战:开始时间
  1648. CSPTime CStrategy::RealGetBeginTime( )
  1649. {
  1650. return m_RealBeginTime;
  1651. }
  1652. // 策略实战:当前时间
  1653. CSPTime CStrategy::RealGetCurrentTime( )
  1654. {
  1655. return m_RealCurrentTime;
  1656. }
  1657. // 策略实战:当前资金
  1658. double CStrategy::RealGetCurrentCash( )
  1659. {
  1660. return m_RealCurrentCash;
  1661. }
  1662. // 策略实战:执行一个操作
  1663. BOOL CStrategy::RealOperate( OPRECORD record, BOOL bTimeStrict )
  1664. {
  1665. if( bTimeStrict && m_RealOpRecord.GetSize() > 0 && record.time < m_RealOpRecord.ElementAt(m_RealOpRecord.GetSize()-1).time )
  1666. return FALSE;
  1667. CStockInfo info;
  1668. if( strlen(record.szCode)>0
  1669. && ( !AfxGetStockContainer().GetStockInfo( record.szCode, &info )
  1670. || !info.IsValidStock() ) )
  1671. return FALSE;
  1672. double dAmount = record.dwShare * record.dSharePrice;
  1673. double dRateCost = record.dRateCost;
  1674. if( STRATEGY_OPTYPE_BUY == record.lOpType ) // 买入
  1675. {
  1676. if( m_RealCurrentCash < dAmount+dRateCost )
  1677. return FALSE;
  1678. if( !m_RealStockOwn.AddStock( info, record.dwShare, record.dSharePrice ) )
  1679. return FALSE;
  1680. m_RealCurrentCash -= (dAmount+dRateCost);
  1681. }
  1682. else if( STRATEGY_OPTYPE_SELL == record.lOpType ) // 卖出
  1683. {
  1684. if( !m_RealStockOwn.RemoveStock( info, record.dwShare ) )
  1685. return FALSE;
  1686. m_RealCurrentCash += (dAmount-dRateCost);
  1687. }
  1688. else if( STRATEGY_OPTYPE_ADDSTOCK == record.lOpType ) // 添加股票
  1689. {
  1690. if( !m_RealStockOwn.AddStock( info, record.dwShare, record.dSharePrice ) )
  1691. return FALSE;
  1692. }
  1693. else if( STRATEGY_OPTYPE_REMOVESTOCK == record.lOpType ) // 移除股票
  1694. {
  1695. if( !m_RealStockOwn.RemoveStock( info, record.dwShare ) )
  1696. return FALSE;
  1697. }
  1698. else if( STRATEGY_OPTYPE_ADDCASH == record.lOpType ) // 加入资金
  1699. {
  1700. m_RealCurrentCash += record.dSharePrice;
  1701. }
  1702. else if( STRATEGY_OPTYPE_REMOVECASH == record.lOpType ) // 移除资金
  1703. {
  1704. if( m_RealCurrentCash < record.dSharePrice )
  1705. return FALSE;
  1706. m_RealCurrentCash -= record.dSharePrice;
  1707. }
  1708. else
  1709. return FALSE;
  1710. // Record
  1711. m_RealOpRecord.Add( record );
  1712. return TRUE;
  1713. }
  1714. // 策略实战:操作记录
  1715. COpRecordContainer & CStrategy::RealGetOpRecord( )
  1716. {
  1717. return m_RealOpRecord;
  1718. }
  1719. // 策略实战:下一步操作计划
  1720. COpRecordContainer & CStrategy::RealGetNextOp( )
  1721. {
  1722. return m_RealNextOp;
  1723. }
  1724. // 策略实战:当前拥有股票
  1725. CStockOwnContainer & CStrategy::RealGetStockOwn( )
  1726. {
  1727. return m_RealStockOwn;
  1728. }
  1729. // 策略实战:总资产序列
  1730. CAssetSerialContainer & CStrategy::RealGetAssetSerial( )
  1731. {
  1732. return m_RealAssetSerial;
  1733. }
  1734. // 策略实战:得到指定日期的总资产
  1735. double CStrategy::RealGetAsset( CSPTime tmCur )
  1736. {
  1737. double dAsset = 0;
  1738. if( m_techstocks.GetSumAsset( tmCur, m_RealStockOwn, &dAsset ) )
  1739. {
  1740. dAsset += m_RealCurrentCash;
  1741. ASSETSERIAL serial;
  1742. memset( &serial, 0, sizeof(serial) );
  1743. serial.time = tmCur.GetTime();
  1744. serial.dAsset = dAsset;
  1745. serial.dCash = m_RealCurrentCash;
  1746. m_RealAssetSerial.SortInsert( serial );
  1747. return dAsset;
  1748. }
  1749. else
  1750. {
  1751. for( int i=m_RealAssetSerial.GetSize()-1; i>=0; i-- )
  1752. {
  1753. ASSETSERIAL & serial = m_RealAssetSerial.ElementAt(i);
  1754. if( serial.time <= tmCur.GetTime() )
  1755. return serial.dAsset;
  1756. }
  1757. }
  1758. return m_opparam.m_nStartAmount;
  1759. }
  1760. // 策略实战:当前收益
  1761. double CStrategy::RealGetCurrentYield( )
  1762. {
  1763. if( m_opparam.m_nStartAmount > 0 )
  1764. return STRATEGY_BASEF_YIELD * RealGetAsset(RealGetCurrentTime()) / m_opparam.m_nStartAmount;
  1765. return STRATEGY_BASEF_YIELD;
  1766. }
  1767. // 策略实战:当前指数上涨百分比
  1768. double CStrategy::RealGetCurrentYieldIndexPercent( )
  1769. {
  1770. CSPTime sptmBegin( RealGetBeginTime().GetTime() );
  1771. CSPTime sptmNow( RealGetCurrentTime().GetTime() );
  1772. DWORD dateBegin = sptmBegin.ToStockTimeDay();
  1773. DWORD dateNow = sptmNow.ToStockTimeDay();
  1774. CKData & kdata = AfxGetStockMain().GetKData(m_opparam.m_nKType);
  1775. int nIndexBegin = kdata.GetAboutIndexByDate( dateBegin );
  1776. int nIndexNow = kdata.GetAboutIndexByDate( dateNow );
  1777. if( -1 == nIndexBegin || -1 == nIndexNow )
  1778. return 0;
  1779. if( kdata.ElementAt(nIndexBegin).m_fClose < 1e-4 )
  1780. return 0;
  1781. double dYield = ((double)kdata.ElementAt(nIndexNow).m_fClose) - kdata.ElementAt(nIndexBegin).m_fClose;
  1782. dYield = dYield / kdata.ElementAt(nIndexBegin).m_fClose;
  1783. return dYield;
  1784. }
  1785. // 策略实战:当前收益百分比
  1786. double CStrategy::RealGetCurrentYieldPercent( )
  1787. {
  1788. return ( RealGetCurrentYield() - STRATEGY_BASEF_YIELD ) / STRATEGY_BASEF_YIELD;
  1789. }
  1790. // 策略实战:执行操作计划
  1791. BOOL CStrategy::RealOperateNextop( CSPTime tmCur, COpRecordContainer & nextop, CTechStock & techstock )
  1792. {
  1793. for( int j=0; j<nextop.GetSize(); j++ ) // 依次执行每一个计划
  1794. {
  1795. OPRECORD & record = nextop.ElementAt(j);
  1796. if( STRATEGY_OPTYPE_BUY != record.lOpType && STRATEGY_OPTYPE_SELL != record.lOpType )
  1797. continue;
  1798. if( tmCur.GetTime() >= record.time
  1799. && techstock.m_info.IsEqualTo( CStock::marketUnknown, record.szCode ) )
  1800. {
  1801. if( !record.bViewed ) // Not Viewed
  1802. {
  1803. nextop.RemoveAt(j);
  1804. j --;
  1805. continue;
  1806. }
  1807. if( techstock.IsStopTrading(tmCur) ) // 停牌,转入下一个交易日的计划中
  1808. {
  1809. CSPTime tmNext;
  1810. if( m_opparam.GetNextTradeTime(tmCur, tmNext) )
  1811. record.time = tmNext.GetTime();
  1812. continue;
  1813. }
  1814. double dPriceOK = record.dSharePrice;
  1815. if( techstock.GetPriceOK( record.lOpType, tmCur, record.dwShare, record.dSharePrice, &dPriceOK ) ) // 成交价格
  1816. {
  1817. record.time = tmCur.GetTime();
  1818. record.dSharePrice = dPriceOK;
  1819. record.dRateCost = record.dwShare * record.dSharePrice * m_rate.GetRate(techstock.m_info);
  1820. RealOperate( record );
  1821. }
  1822. else if( STRATEGY_OPTYPE_SELL == record.lOpType ) // 如果是卖出不成功,转入下一个交易日,直至卖出成功
  1823. {
  1824. CSPTime tmNext;
  1825. if( m_opparam.GetNextTradeTime(tmCur, tmNext) )
  1826. record.time = tmNext.GetTime();
  1827. if( techstock.GetClosePrice(tmCur,&dPriceOK) )
  1828. record.dSharePrice = dPriceOK * m_opparam.m_dSellMulti;
  1829. continue;
  1830. }
  1831. nextop.RemoveAt(j);
  1832. j --;
  1833. }
  1834. }
  1835. return TRUE;
  1836. }
  1837. // 策略实战:执行
  1838. BOOL CStrategy::RealRun( SIMULATION_CALLBACK fnCallback, void * cookie )
  1839. {
  1840. // TIMEZONES
  1841. // 准备数据
  1842. if( !PrepareData( fnCallback, cookie ) )
  1843. return FALSE;
  1844. ClearLastIntensity( );
  1845. DWORD dwShare = 0; // Temp Data
  1846. double dSharePrice = 0; // Temp Data
  1847. CSPTime tmOp; // Temp Data
  1848. do {
  1849. CSPTime tmCur = RealGetCurrentTime(); // 当前日期
  1850. // Process
  1851. for( int i=0; i<m_techstocks.GetSize(); i++ ) // 每只股票依次判断
  1852. {
  1853. CTechStock & techstock = m_techstocks.ElementAt(i);
  1854. // Operate
  1855. RealOperateNextop( tmCur, m_RealNextOp, techstock ); // 执行今日操作计划
  1856. // Judge Whether to operate, if yes, save to nextop
  1857. STOCKOWN own;
  1858. memset( &own, 0, sizeof(own) );
  1859. if( m_RealStockOwn.HasThisStock( techstock.m_info, &own ) ) // 如果有这支股票,判断是否卖出
  1860. {
  1861. if( m_techstocks.GetShouldSellShare( techstock, tmCur, own, m_opparam, &tmOp, &dwShare, &dSharePrice ) )
  1862. { // 如果卖出,加入操作计划中
  1863. m_RealNextOp.AddRecordUniqueStock( STRATEGY_OPTYPE_SELL, tmOp, techstock.m_info.GetStockCode(), dwShare, dSharePrice, dwShare*dSharePrice*m_rate.GetRate(techstock.m_info) );
  1864. }
  1865. }
  1866. else // 判断是否买入
  1867. {
  1868. if( m_techstocks.GetShouldBuyShare( techstock, tmCur, m_RealCurrentCash, m_rate , m_opparam, m_RealStockOwn.GetSize(), &tmOp, &dwShare, &dSharePrice )
  1869. && ( m_RealStockOwn.GetSize() + m_RealNextOp.GetBuyRecordCount() < m_opparam.m_nStoreDiv || m_RealNextOp.HasBuyStock(techstock.m_info.GetStockCode()) ) )
  1870. { // 如果买入,加入操作计划中
  1871. m_RealNextOp.AddRecordUniqueStock( STRATEGY_OPTYPE_BUY, tmOp, techstock.m_info.GetStockCode(), dwShare, dSharePrice, dwShare*dSharePrice*m_rate.GetRate(techstock.m_info) );
  1872. }
  1873. }
  1874. // 进度显示
  1875. DWORD dwProgress = (DWORD)((i+1)*STRATEGY_MAX_PROGRESS/m_techstocks.GetSize());
  1876. if( fnCallback && !fnCallback( SIMULATION_PROGRESS, dwProgress, NULL, cookie ) )
  1877. return FALSE;
  1878. }
  1879. RealGetAsset( RealGetCurrentTime() );
  1880. } while( RealGotoNextTime() ); // 下一个交易日
  1881. if( fnCallback )
  1882. fnCallback( SIMULATION_PROGRESS, STRATEGY_MAX_PROGRESS, NULL, cookie );
  1883. return TRUE;
  1884. }
  1885. // 策略实战:加入操作记录,如果成功,同时要删除加入日后的所有操作
  1886. BOOL CStrategy::RealAddOpRecordStrict( OPRECORD record )
  1887. {
  1888. COpRecordContainer recordbk;
  1889. recordbk.Copy( m_RealOpRecord );
  1890. // 重新执行操作记录,到加入新操作日为止
  1891. BOOL bOK = TRUE;
  1892. m_RealCurrentCash = m_opparam.m_nStartAmount;
  1893. m_RealOpRecord.RemoveAll();
  1894. m_RealNextOp.RemoveAll();
  1895. m_RealStockOwn.RemoveAll();
  1896. for( int i=0; i<recordbk.GetSize(); i++ )
  1897. {
  1898. OPRECORD rec = recordbk.ElementAt(i);
  1899. if( bOK && rec.time < record.time )
  1900. bOK &= RealOperate( rec );
  1901. }
  1902. if( bOK && RealOperate( record ) )
  1903. { // 加入成功,重新计算总资产序列
  1904. for( i=m_RealAssetSerial.GetSize()-1; i>=0; i-- )
  1905. {
  1906. ASSETSERIAL serial = m_RealAssetSerial.ElementAt(i);
  1907. if( serial.time >= record.time )
  1908. m_RealAssetSerial.RemoveAt(i);
  1909. }
  1910. RealGetAsset( record.time );
  1911. return TRUE;
  1912. }
  1913. else
  1914. {
  1915. // 加入失败,全部重来,恢复原样
  1916. m_RealCurrentCash = m_opparam.m_nStartAmount;
  1917. m_RealOpRecord.RemoveAll();
  1918. m_RealNextOp.RemoveAll();
  1919. m_RealStockOwn.RemoveAll();
  1920. for( i=0; i<recordbk.GetSize(); i++ )
  1921. {
  1922. OPRECORD rec = recordbk.ElementAt(i);
  1923. RealOperate( rec );
  1924. }
  1925. return FALSE;
  1926. }
  1927. }
  1928. // 策略实战:删除操作记录,如果成功,同时要删除日后的所有操作
  1929. BOOL CStrategy::RealDeleteOpRecordStrict( int nRecord )
  1930. {
  1931. if( nRecord < 0 || nRecord >= m_RealOpRecord.GetSize() )
  1932. {
  1933. SP_ASSERT( FALSE );
  1934. return FALSE;
  1935. }
  1936. OPRECORD record = m_RealOpRecord.ElementAt(nRecord);
  1937. COpRecordContainer recordbk;
  1938. recordbk.Copy( m_RealOpRecord );
  1939. // 重新执行操作记录,到删除日为止
  1940. BOOL bOK = TRUE;
  1941. m_RealCurrentCash = m_opparam.m_nStartAmount;
  1942. m_RealOpRecord.RemoveAll();
  1943. m_RealNextOp.RemoveAll();
  1944. m_RealStockOwn.RemoveAll();
  1945. for( int i=0; i<recordbk.GetSize(); i++ )
  1946. {
  1947. OPRECORD rec = recordbk.ElementAt(i);
  1948. if( bOK && rec.time < record.time )
  1949. bOK &= RealOperate( rec );
  1950. }
  1951. if( bOK )
  1952. { // 成功删除,重新计算总资产序列
  1953. for( i=m_RealAssetSerial.GetSize()-1; i>=0; i-- )
  1954. {
  1955. ASSETSERIAL serial = m_RealAssetSerial.ElementAt(i);
  1956. if( serial.time >= record.time )
  1957. m_RealAssetSerial.RemoveAt(i);
  1958. }
  1959. RealGetAsset( record.time );
  1960. return TRUE;
  1961. }
  1962. else
  1963. {
  1964. // 删除失败,恢复原样
  1965. m_RealCurrentCash = m_opparam.m_nStartAmount;
  1966. m_RealOpRecord.RemoveAll();
  1967. m_RealNextOp.RemoveAll();
  1968. m_RealStockOwn.RemoveAll();
  1969. for( i=0; i<recordbk.GetSize(); i++ )
  1970. {
  1971. OPRECORD rec = recordbk.ElementAt(i);
  1972. RealOperate( rec );
  1973. }
  1974. return FALSE;
  1975. }
  1976. }
  1977. /*
  1978. BOOL CStrategy::RealUnOperate( OPRECORD record )
  1979. {
  1980. CStockInfo info;
  1981. if( strlen(record.szCode)>0
  1982. && ( !AfxGetStockContainer().GetStockInfo( record.szCode, &info )
  1983. || !info.IsValidStock() ) )
  1984. return FALSE;
  1985. double dAmount = record.dwShare * record.dSharePrice;
  1986. double dRateCost = record.dRateCost;
  1987. if( STRATEGY_OPTYPE_BUY == record.lOpType )
  1988. {
  1989. if( !m_RealStockOwn.RemoveStock( info, record.dwShare ) )
  1990. return FALSE;
  1991. m_RealCurrentCash += (dAmount+dRateCost);
  1992. }
  1993. else if( STRATEGY_OPTYPE_SELL == record.lOpType )
  1994. {
  1995. if( m_RealCurrentCash < dAmount-dRateCost )
  1996. return FALSE;
  1997. if( !m_RealStockOwn.AddStock( info, record.dwShare ) )
  1998. return FALSE;
  1999. m_RealCurrentCash -= (dAmount-dRateCost);
  2000. }
  2001. else if( STRATEGY_OPTYPE_ADDSTOCK == record.lOpType )
  2002. {
  2003. if( !m_RealStockOwn.RemoveStock( info, record.dwShare ) )
  2004. return FALSE;
  2005. }
  2006. else if( STRATEGY_OPTYPE_REMOVESTOCK == record.lOpType )
  2007. {
  2008. if( !m_RealStockOwn.AddStock( info, record.dwShare ) )
  2009. return FALSE;
  2010. }
  2011. else if( STRATEGY_OPTYPE_ADDCASH == record.lOpType )
  2012. {
  2013. if( m_RealCurrentCash < record.dSharePrice )
  2014. return FALSE;
  2015. m_RealCurrentCash -= record.dSharePrice;
  2016. }
  2017. else if( STRATEGY_OPTYPE_REMOVECASH == record.lOpType )
  2018. {
  2019. m_RealCurrentCash += record.dSharePrice;
  2020. }
  2021. else
  2022. return FALSE;
  2023. return TRUE;
  2024. }
  2025. BOOL CStrategy::RealAddOpRecordStrict( OPRECORD record )
  2026. {
  2027. COpRecordContainer recordbk;
  2028. recordbk.Copy( m_RealOpRecord );
  2029. BOOL bOK = TRUE;
  2030. for( int i=m_RealOpRecord.GetSize()-1; i>=0; i-- )
  2031. {
  2032. OPRECORD rec = m_RealOpRecord.ElementAt(i);
  2033. if( bOK && rec.time > record.time )
  2034. {
  2035. bOK &= RealUnOperate( rec );
  2036. if( bOK )
  2037. m_RealOpRecord.RemoveAt(i);
  2038. }
  2039. }
  2040. if( bOK && RealOperate( record ) )
  2041. {
  2042. for( i=m_RealAssetSerial.GetSize()-1; i>=0; i-- )
  2043. {
  2044. ASSETSERIAL serial = m_RealAssetSerial.ElementAt(i);
  2045. if( serial.time >= record.time )
  2046. m_RealAssetSerial.RemoveAt(i);
  2047. }
  2048. RealGetAsset( record.time );
  2049. return TRUE;
  2050. }
  2051. else
  2052. {
  2053. // Restore
  2054. m_RealCurrentCash = m_opparam.m_nStartAmount;
  2055. m_RealOpRecord.RemoveAll();
  2056. m_RealNextOp.RemoveAll();
  2057. m_RealStockOwn.RemoveAll();
  2058. for( i=0; i<recordbk.GetSize(); i++ )
  2059. {
  2060. OPRECORD rec = recordbk.ElementAt(i);
  2061. RealOperate( rec );
  2062. }
  2063. return FALSE;
  2064. }
  2065. }
  2066. BOOL CStrategy::RealDeleteOpRecordStrict( int nRecord )
  2067. {
  2068. if( nRecord < 0 || nRecord >= m_RealOpRecord.GetSize() )
  2069. {
  2070. SP_ASSERT( FALSE );
  2071. return FALSE;
  2072. }
  2073. COpRecordContainer recordbk;
  2074. recordbk.Copy( m_RealOpRecord );
  2075. BOOL bOK = TRUE;
  2076. OPRECORD record = m_RealOpRecord.ElementAt(nRecord);
  2077. for( int i=m_RealOpRecord.GetSize()-1; i>=0; i-- )
  2078. {
  2079. OPRECORD rec = m_RealOpRecord.ElementAt(i);
  2080. if( bOK && rec.time >= record.time )
  2081. {
  2082. bOK &= RealUnOperate( rec );
  2083. if( bOK )
  2084. m_RealOpRecord.RemoveAt(i);
  2085. }
  2086. }
  2087. if( bOK )
  2088. {
  2089. for( i=m_RealAssetSerial.GetSize()-1; i>=0; i-- )
  2090. {
  2091. ASSETSERIAL serial = m_RealAssetSerial.ElementAt(i);
  2092. if( serial.time >= record.time )
  2093. m_RealAssetSerial.RemoveAt(i);
  2094. }
  2095. return TRUE;
  2096. }
  2097. else
  2098. {
  2099. // Restore
  2100. m_RealCurrentCash = m_opparam.m_nStartAmount;
  2101. m_RealOpRecord.RemoveAll();
  2102. m_RealNextOp.RemoveAll();
  2103. m_RealStockOwn.RemoveAll();
  2104. for( i=0; i<recordbk.GetSize(); i++ )
  2105. {
  2106. OPRECORD rec = recordbk.ElementAt(i);
  2107. RealOperate( rec );
  2108. }
  2109. return FALSE;
  2110. }
  2111. }
  2112. */